summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c')
-rw-r--r--MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c8674
1 files changed, 4337 insertions, 4337 deletions
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
index a7b7dc743a..7158949075 100644
--- a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
+++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
@@ -1,4337 +1,4337 @@
-/** @file
-Entry and initialization module for the browser.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FormDisplay.h"
-
-//
-// Search table for UiDisplayMenu()
-//
-SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
- {
- SCAN_UP,
- UiUp,
- },
- {
- SCAN_DOWN,
- UiDown,
- },
- {
- SCAN_PAGE_UP,
- UiPageUp,
- },
- {
- SCAN_PAGE_DOWN,
- UiPageDown,
- },
- {
- SCAN_ESC,
- UiReset,
- },
- {
- SCAN_LEFT,
- UiLeft,
- },
- {
- SCAN_RIGHT,
- UiRight,
- }
-};
-
-UINTN mScanCodeNumber = ARRAY_SIZE (gScanCodeToOperation);
-
-SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
- {
- UiNoOperation,
- CfUiNoOperation,
- },
- {
- UiSelect,
- CfUiSelect,
- },
- {
- UiUp,
- CfUiUp,
- },
- {
- UiDown,
- CfUiDown,
- },
- {
- UiLeft,
- CfUiLeft,
- },
- {
- UiRight,
- CfUiRight,
- },
- {
- UiReset,
- CfUiReset,
- },
- {
- UiPageUp,
- CfUiPageUp,
- },
- {
- UiPageDown,
- CfUiPageDown
- },
- {
- UiHotKey,
- CfUiHotKey
- }
-};
-
-EFI_GUID gDisplayEngineGuid = {
- 0xE38C1029, 0xE38F, 0x45b9, { 0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62 }
-};
-
-BOOLEAN gMisMatch;
-EFI_SCREEN_DESCRIPTOR gStatementDimensions;
-BOOLEAN mStatementLayoutIsChanged = TRUE;
-USER_INPUT *gUserInput;
-FORM_DISPLAY_ENGINE_FORM *gFormData;
-EFI_HII_HANDLE gHiiHandle;
-UINT16 gDirection;
-LIST_ENTRY gMenuOption;
-DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = { 0 };
-BOOLEAN mIsFirstForm = TRUE;
-FORM_ENTRY_INFO gOldFormEntry = { 0 };
-
-//
-// Browser Global Strings
-//
-CHAR16 *gReconnectConfirmChanges;
-CHAR16 *gReconnectFail;
-CHAR16 *gReconnectRequired;
-CHAR16 *gChangesOpt;
-CHAR16 *gFormNotFound;
-CHAR16 *gNoSubmitIf;
-CHAR16 *gBrowserError;
-CHAR16 *gSaveFailed;
-CHAR16 *gNoSubmitIfFailed;
-CHAR16 *gSaveProcess;
-CHAR16 *gSaveNoSubmitProcess;
-CHAR16 *gDiscardChange;
-CHAR16 *gJumpToFormSet;
-CHAR16 *gCheckError;
-CHAR16 *gPromptForData;
-CHAR16 *gPromptForPassword;
-CHAR16 *gPromptForNewPassword;
-CHAR16 *gConfirmPassword;
-CHAR16 *gConfirmError;
-CHAR16 *gPassowordInvalid;
-CHAR16 *gPressEnter;
-CHAR16 *gEmptyString;
-CHAR16 *gMiniString;
-CHAR16 *gOptionMismatch;
-CHAR16 *gFormSuppress;
-CHAR16 *gProtocolNotFound;
-CHAR16 *gConfirmDefaultMsg;
-CHAR16 *gConfirmSubmitMsg;
-CHAR16 *gConfirmDiscardMsg;
-CHAR16 *gConfirmResetMsg;
-CHAR16 *gConfirmExitMsg;
-CHAR16 *gConfirmSubmitMsg2nd;
-CHAR16 *gConfirmDefaultMsg2nd;
-CHAR16 *gConfirmResetMsg2nd;
-CHAR16 *gConfirmExitMsg2nd;
-CHAR16 *gConfirmOpt;
-CHAR16 *gConfirmOptYes;
-CHAR16 *gConfirmOptNo;
-CHAR16 *gConfirmOptOk;
-CHAR16 *gConfirmOptCancel;
-CHAR16 *gYesOption;
-CHAR16 *gNoOption;
-CHAR16 *gOkOption;
-CHAR16 *gCancelOption;
-CHAR16 *gErrorPopup;
-CHAR16 *gWarningPopup;
-CHAR16 *gInfoPopup;
-CHAR16 *gConfirmMsgConnect;
-CHAR16 *gConfirmMsgEnd;
-CHAR16 *gPasswordUnsupported;
-CHAR16 gModalSkipColumn;
-CHAR16 gPromptBlockWidth;
-CHAR16 gOptionBlockWidth;
-CHAR16 gHelpBlockWidth;
-CHAR16 *mUnknownString;
-
-FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {
- FORM_DISPLAY_DRIVER_SIGNATURE,
- NULL,
- {
- FormDisplay,
- DriverClearDisplayPage,
- ConfirmDataChange
- },
- {
- EFI_HII_POPUP_PROTOCOL_REVISION,
- CreatePopup
- }
-};
-
-/**
- Get the string based on the StringId and HII Package List Handle.
-
- @param Token The String's ID.
- @param HiiHandle The package list in the HII database to search for
- the specified string.
-
- @return The output string.
-
-**/
-CHAR16 *
-GetToken (
- IN EFI_STRING_ID Token,
- IN EFI_HII_HANDLE HiiHandle
- )
-{
- EFI_STRING String;
-
- String = HiiGetString (HiiHandle, Token, NULL);
- if (String == NULL) {
- String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
- ASSERT (String != NULL);
- }
-
- return (CHAR16 *)String;
-}
-
-/**
- Initialize the HII String Token to the correct values.
-
-**/
-VOID
-InitializeDisplayStrings (
- VOID
- )
-{
- gReconnectConfirmChanges = GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES), gHiiHandle);
- mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);
- gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
- gNoSubmitIfFailed = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle);
- gReconnectFail = GetToken (STRING_TOKEN (RECONNECT_FAILED), gHiiHandle);
- gReconnectRequired = GetToken (STRING_TOKEN (RECONNECT_REQUIRED), gHiiHandle);
- gChangesOpt = GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS), gHiiHandle);
- gSaveProcess = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle);
- gSaveNoSubmitProcess = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle);
- gDiscardChange = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle);
- gJumpToFormSet = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle);
- gCheckError = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle);
- gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);
- gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);
- gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);
- gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);
- gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);
- gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);
- gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);
- gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
- gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
- gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);
- gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);
- gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);
- gFormNotFound = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle);
- gNoSubmitIf = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle);
- gBrowserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);
- gConfirmDefaultMsg = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE), gHiiHandle);
- gConfirmDiscardMsg = GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE), gHiiHandle);
- gConfirmSubmitMsg = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE), gHiiHandle);
- gConfirmResetMsg = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE), gHiiHandle);
- gConfirmExitMsg = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE), gHiiHandle);
- gConfirmDefaultMsg2nd = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND), gHiiHandle);
- gConfirmSubmitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND), gHiiHandle);
- gConfirmResetMsg2nd = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND), gHiiHandle);
- gConfirmExitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND), gHiiHandle);
- gConfirmOpt = GetToken (STRING_TOKEN (CONFIRM_OPTION), gHiiHandle);
- gConfirmOptYes = GetToken (STRING_TOKEN (CONFIRM_OPTION_YES), gHiiHandle);
- gConfirmOptNo = GetToken (STRING_TOKEN (CONFIRM_OPTION_NO), gHiiHandle);
- gConfirmOptOk = GetToken (STRING_TOKEN (CONFIRM_OPTION_OK), gHiiHandle);
- gConfirmOptCancel = GetToken (STRING_TOKEN (CONFIRM_OPTION_CANCEL), gHiiHandle);
- gYesOption = GetToken (STRING_TOKEN (YES_SELECTABLE_OPTION), gHiiHandle);
- gNoOption = GetToken (STRING_TOKEN (NO_SELECTABLE_OPTION), gHiiHandle);
- gOkOption = GetToken (STRING_TOKEN (OK_SELECTABLE_OPTION), gHiiHandle);
- gCancelOption = GetToken (STRING_TOKEN (CANCEL_SELECTABLE_OPTION), gHiiHandle);
- gErrorPopup = GetToken (STRING_TOKEN (ERROR_POPUP_STRING), gHiiHandle);
- gWarningPopup = GetToken (STRING_TOKEN (WARNING_POPUP_STRING), gHiiHandle);
- gInfoPopup = GetToken (STRING_TOKEN (INFO_POPUP_STRING), gHiiHandle);
- gConfirmMsgConnect = GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT), gHiiHandle);
- gConfirmMsgEnd = GetToken (STRING_TOKEN (CONFIRM_OPTION_END), gHiiHandle);
- gPasswordUnsupported = GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED), gHiiHandle);
-}
-
-/**
- Free up the resource allocated for all strings required
- by Setup Browser.
-
-**/
-VOID
-FreeDisplayStrings (
- VOID
- )
-{
- FreePool (mUnknownString);
- FreePool (gEmptyString);
- FreePool (gSaveFailed);
- FreePool (gNoSubmitIfFailed);
- FreePool (gReconnectFail);
- FreePool (gReconnectRequired);
- FreePool (gChangesOpt);
- FreePool (gReconnectConfirmChanges);
- FreePool (gSaveProcess);
- FreePool (gSaveNoSubmitProcess);
- FreePool (gDiscardChange);
- FreePool (gJumpToFormSet);
- FreePool (gCheckError);
- FreePool (gPromptForData);
- FreePool (gPromptForPassword);
- FreePool (gPromptForNewPassword);
- FreePool (gConfirmPassword);
- FreePool (gConfirmError);
- FreePool (gPassowordInvalid);
- FreePool (gPressEnter);
- FreePool (gMiniString);
- FreePool (gOptionMismatch);
- FreePool (gFormSuppress);
- FreePool (gProtocolNotFound);
- FreePool (gBrowserError);
- FreePool (gNoSubmitIf);
- FreePool (gFormNotFound);
- FreePool (gConfirmDefaultMsg);
- FreePool (gConfirmSubmitMsg);
- FreePool (gConfirmDiscardMsg);
- FreePool (gConfirmResetMsg);
- FreePool (gConfirmExitMsg);
- FreePool (gConfirmDefaultMsg2nd);
- FreePool (gConfirmSubmitMsg2nd);
- FreePool (gConfirmResetMsg2nd);
- FreePool (gConfirmExitMsg2nd);
- FreePool (gConfirmOpt);
- FreePool (gConfirmOptYes);
- FreePool (gConfirmOptNo);
- FreePool (gConfirmOptOk);
- FreePool (gConfirmOptCancel);
- FreePool (gYesOption);
- FreePool (gNoOption);
- FreePool (gOkOption);
- FreePool (gCancelOption);
- FreePool (gErrorPopup);
- FreePool (gWarningPopup);
- FreePool (gInfoPopup);
- FreePool (gConfirmMsgConnect);
- FreePool (gConfirmMsgEnd);
- FreePool (gPasswordUnsupported);
-}
-
-/**
- Get prompt string id from the opcode data buffer.
-
- @param OpCode The input opcode buffer.
-
- @return The prompt string id.
-
-**/
-EFI_STRING_ID
-GetPrompt (
- IN EFI_IFR_OP_HEADER *OpCode
- )
-{
- EFI_IFR_STATEMENT_HEADER *Header;
-
- if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {
- return 0;
- }
-
- Header = (EFI_IFR_STATEMENT_HEADER *)(OpCode + 1);
-
- return Header->Prompt;
-}
-
-/**
- Get the supported width for a particular op-code
-
- @param MenuOption The menu option.
- @param AdjustWidth The width which is saved for the space.
-
- @return Returns the number of CHAR16 characters that is support.
-
-**/
-UINT16
-GetWidth (
- IN UI_MENU_OPTION *MenuOption,
- OUT UINT16 *AdjustWidth
- )
-{
- CHAR16 *String;
- UINTN Size;
- EFI_IFR_TEXT *TextOp;
- UINT16 ReturnWidth;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
-
- Statement = MenuOption->ThisTag;
-
- //
- // For modal form, clean the entire row.
- //
- if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- if (AdjustWidth != NULL) {
- *AdjustWidth = LEFT_SKIPPED_COLUMNS;
- }
-
- return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gModalSkipColumn + LEFT_SKIPPED_COLUMNS));
- }
-
- Size = 0;
-
- //
- // See if the second text parameter is really NULL
- //
- if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
- TextOp = (EFI_IFR_TEXT *)Statement->OpCode;
- if (TextOp->TextTwo != 0) {
- String = GetToken (TextOp->TextTwo, gFormData->HiiHandle);
- Size = StrLen (String);
- FreePool (String);
- }
- }
-
- if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
- //
- // Allow a wide display if text op-code and no secondary text op-code
- //
- ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
- )
- {
- //
- // Return the space width.
- //
- if (AdjustWidth != NULL) {
- *AdjustWidth = 2;
- }
-
- //
- // Keep consistent with current behavior.
- //
- ReturnWidth = (UINT16)(gPromptBlockWidth + gOptionBlockWidth - 2);
- } else {
- if (AdjustWidth != NULL) {
- *AdjustWidth = 1;
- }
-
- ReturnWidth = (UINT16)(gPromptBlockWidth - 1);
- }
-
- //
- // For nest in statement, should the subtitle indent.
- //
- if (MenuOption->NestInStatement) {
- ReturnWidth -= SUBTITLE_INDENT;
- }
-
- return ReturnWidth;
-}
-
-/**
- Will copy LineWidth amount of a string in the OutputString buffer and return the
- number of CHAR16 characters that were copied into the OutputString buffer.
- The output string format is:
- Glyph Info + String info + '\0'.
-
- In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
-
- @param InputString String description for this option.
- @param LineWidth Width of the desired string to extract in CHAR16
- characters
- @param GlyphWidth The glyph width of the begin of the char in the string.
- @param Index Where in InputString to start the copy process
- @param OutputString Buffer to copy the string into
-
- @return Returns the number of CHAR16 characters that were copied into the OutputString
- buffer, include extra glyph info and '\0' info.
-
-**/
-UINT16
-GetLineByWidth (
- IN CHAR16 *InputString,
- IN UINT16 LineWidth,
- IN OUT UINT16 *GlyphWidth,
- IN OUT UINTN *Index,
- OUT CHAR16 **OutputString
- )
-{
- UINT16 StrOffset;
- UINT16 GlyphOffset;
- UINT16 OriginalGlyphWidth;
- BOOLEAN ReturnFlag;
- UINT16 LastSpaceOffset;
- UINT16 LastGlyphWidth;
-
- if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) {
- return 0;
- }
-
- if ((LineWidth == 0) || (*GlyphWidth == 0)) {
- return 0;
- }
-
- //
- // Save original glyph width.
- //
- OriginalGlyphWidth = *GlyphWidth;
- LastGlyphWidth = OriginalGlyphWidth;
- ReturnFlag = FALSE;
- LastSpaceOffset = 0;
-
- //
- // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.
- // To avoid displaying this empty line in screen, just skip the two CHARs here.
- //
- if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
- *Index = *Index + 2;
- }
-
- //
- // Fast-forward the string and see if there is a carriage-return in the string
- //
- for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {
- switch (InputString[*Index + StrOffset]) {
- case NARROW_CHAR:
- *GlyphWidth = 1;
- break;
-
- case WIDE_CHAR:
- *GlyphWidth = 2;
- break;
-
- case CHAR_CARRIAGE_RETURN:
- case CHAR_LINEFEED:
- case CHAR_NULL:
- ReturnFlag = TRUE;
- break;
-
- default:
- GlyphOffset = GlyphOffset + *GlyphWidth;
-
- //
- // Record the last space info in this line. Will be used in rewind.
- //
- if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {
- LastSpaceOffset = StrOffset;
- LastGlyphWidth = *GlyphWidth;
- }
-
- break;
- }
-
- if (ReturnFlag) {
- break;
- }
- }
-
- //
- // Rewind the string from the maximum size until we see a space to break the line
- //
- if (GlyphOffset > LineWidth) {
- //
- // Rewind the string to last space char in this line.
- //
- if (LastSpaceOffset != 0) {
- StrOffset = LastSpaceOffset;
- *GlyphWidth = LastGlyphWidth;
- } else {
- //
- // Roll back to last char in the line width.
- //
- StrOffset--;
- }
- }
-
- //
- // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
- //
- if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) {
- return 0;
- }
-
- //
- // Need extra glyph info and '\0' info, so +2.
- //
- *OutputString = AllocateZeroPool ((StrOffset + 2) * sizeof (CHAR16));
- if (*OutputString == NULL) {
- return 0;
- }
-
- //
- // Save the glyph info at the begin of the string, will used by Print function.
- //
- if (OriginalGlyphWidth == 1) {
- *(*OutputString) = NARROW_CHAR;
- } else {
- *(*OutputString) = WIDE_CHAR;
- }
-
- CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof (CHAR16));
-
- if (InputString[*Index + StrOffset] == CHAR_SPACE) {
- //
- // Skip the space info at the begin of next line.
- //
- *Index = (UINT16)(*Index + StrOffset + 1);
- } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
- //
- // Skip the /n or /n/r info.
- //
- if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
- *Index = (UINT16)(*Index + StrOffset + 2);
- } else {
- *Index = (UINT16)(*Index + StrOffset + 1);
- }
- } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {
- //
- // Skip the /r or /r/n info.
- //
- if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {
- *Index = (UINT16)(*Index + StrOffset + 2);
- } else {
- *Index = (UINT16)(*Index + StrOffset + 1);
- }
- } else {
- *Index = (UINT16)(*Index + StrOffset);
- }
-
- //
- // Include extra glyph info and '\0' info, so +2.
- //
- return StrOffset + 2;
-}
-
-/**
- Add one menu option by specified description and context.
-
- @param Statement Statement of this Menu Option.
- @param MenuItemCount The index for this Option in the Menu.
- @param NestIn Whether this statement is nest in another statement.
-
-**/
-VOID
-UiAddMenuOption (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
- IN UINT16 *MenuItemCount,
- IN BOOLEAN NestIn
- )
-{
- UI_MENU_OPTION *MenuOption;
- UINTN Index;
- UINTN Count;
- UINT16 NumberOfLines;
- UINT16 GlyphWidth;
- UINT16 Width;
- UINTN ArrayEntry;
- CHAR16 *OutputString;
- EFI_STRING_ID PromptId;
-
- NumberOfLines = 1;
- ArrayEntry = 0;
- GlyphWidth = 1;
- Count = 1;
- MenuOption = NULL;
-
- PromptId = GetPrompt (Statement->OpCode);
- ASSERT (PromptId != 0);
-
- if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- Count = 3;
- }
-
- for (Index = 0; Index < Count; Index++) {
- MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
- ASSERT (MenuOption);
-
- MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
- MenuOption->Description = GetToken (PromptId, gFormData->HiiHandle);
- MenuOption->Handle = gFormData->HiiHandle;
- MenuOption->ThisTag = Statement;
- MenuOption->NestInStatement = NestIn;
- MenuOption->EntryNumber = *MenuItemCount;
-
- MenuOption->Sequence = Index;
-
- if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {
- MenuOption->GrayOut = TRUE;
- } else {
- MenuOption->GrayOut = FALSE;
- }
-
- if (((Statement->Attribute & HII_DISPLAY_LOCK) != 0) || ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0)) {
- MenuOption->GrayOut = TRUE;
- }
-
- //
- // If the form or the question has the lock attribute, deal same as grayout.
- //
- if (((gFormData->Attribute & HII_DISPLAY_LOCK) != 0) || ((Statement->Attribute & HII_DISPLAY_LOCK) != 0)) {
- MenuOption->GrayOut = TRUE;
- }
-
- switch (Statement->OpCode->OpCode) {
- case EFI_IFR_ORDERED_LIST_OP:
- case EFI_IFR_ONE_OF_OP:
- case EFI_IFR_NUMERIC_OP:
- case EFI_IFR_TIME_OP:
- case EFI_IFR_DATE_OP:
- case EFI_IFR_CHECKBOX_OP:
- case EFI_IFR_PASSWORD_OP:
- case EFI_IFR_STRING_OP:
- //
- // User could change the value of these items
- //
- MenuOption->IsQuestion = TRUE;
- break;
- case EFI_IFR_TEXT_OP:
- if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {
- //
- // Initializing GrayOut option as TRUE for Text setup options
- // so that those options will be Gray in colour and un selectable.
- //
- MenuOption->GrayOut = TRUE;
- }
-
- break;
- default:
- MenuOption->IsQuestion = FALSE;
- break;
- }
-
- if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {
- MenuOption->ReadOnly = TRUE;
- if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {
- MenuOption->GrayOut = TRUE;
- }
- }
-
- if ((Index == 0) &&
- (Statement->OpCode->OpCode != EFI_IFR_DATE_OP) &&
- (Statement->OpCode->OpCode != EFI_IFR_TIME_OP))
- {
- Width = GetWidth (MenuOption, NULL);
- for ( ; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &ArrayEntry, &OutputString) != 0x0000;) {
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&MenuOption->Description[ArrayEntry]) != 0) {
- NumberOfLines++;
- }
-
- FreePool (OutputString);
- }
- } else {
- //
- // Add three MenuOptions for Date/Time
- // Data format : [01/02/2004] [11:22:33]
- // Line number : 0 0 1 0 0 1
- //
- NumberOfLines = 0;
- }
-
- if (Index == 2) {
- //
- // Override LineNumber for the MenuOption in Date/Time sequence
- //
- MenuOption->Skip = 1;
- } else {
- MenuOption->Skip = NumberOfLines;
- }
-
- InsertTailList (&gMenuOption, &MenuOption->Link);
- }
-
- (*MenuItemCount)++;
-}
-
-/**
- Create the menu list base on the form data info.
-
-**/
-VOID
-ConvertStatementToMenu (
- VOID
- )
-{
- UINT16 MenuItemCount;
- LIST_ENTRY *Link;
- LIST_ENTRY *NestLink;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
-
- MenuItemCount = 0;
- InitializeListHead (&gMenuOption);
-
- Link = GetFirstNode (&gFormData->StatementListHead);
- while (!IsNull (&gFormData->StatementListHead, Link)) {
- Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
- Link = GetNextNode (&gFormData->StatementListHead, Link);
-
- //
- // Skip the opcode not recognized by Display core.
- //
- if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {
- continue;
- }
-
- UiAddMenuOption (Statement, &MenuItemCount, FALSE);
-
- //
- // Check the statement nest in this host statement.
- //
- NestLink = GetFirstNode (&Statement->NestStatementList);
- while (!IsNull (&Statement->NestStatementList, NestLink)) {
- NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
- NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
-
- //
- // Skip the opcode not recognized by Display core.
- //
- if (NestStatement->OpCode->OpCode == EFI_IFR_GUID_OP) {
- continue;
- }
-
- UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);
- }
- }
-}
-
-/**
- Count the storage space of a Unicode string.
-
- This function handles the Unicode string with NARROW_CHAR
- and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
- does not count in the resultant output. If a WIDE_CHAR is
- hit, then 2 Unicode character will consume an output storage
- space with size of CHAR16 till a NARROW_CHAR is hit.
-
- If String is NULL, then ASSERT ().
-
- @param String The input string to be counted.
-
- @return Storage space for the input string.
-
-**/
-UINTN
-GetStringWidth (
- IN CHAR16 *String
- )
-{
- UINTN Index;
- UINTN Count;
- UINTN IncrementValue;
-
- ASSERT (String != NULL);
- if (String == NULL) {
- return 0;
- }
-
- Index = 0;
- Count = 0;
- IncrementValue = 1;
-
- do {
- //
- // Advance to the null-terminator or to the first width directive
- //
- for ( ;
- (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
- Index++, Count = Count + IncrementValue
- )
- {
- }
-
- //
- // We hit the null-terminator, we now have a count
- //
- if (String[Index] == 0) {
- break;
- }
-
- //
- // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
- // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
- //
- if (String[Index] == NARROW_CHAR) {
- //
- // Skip to the next character
- //
- Index++;
- IncrementValue = 1;
- } else {
- //
- // Skip to the next character
- //
- Index++;
- IncrementValue = 2;
- }
- } while (String[Index] != 0);
-
- //
- // Increment by one to include the null-terminator in the size
- //
- Count++;
-
- return Count * sizeof (CHAR16);
-}
-
-/**
- Base on the input option string to update the skip value for a menu option.
-
- @param MenuOption The MenuOption to be checked.
- @param OptionString The input option string.
-
-**/
-VOID
-UpdateSkipInfoForMenu (
- IN UI_MENU_OPTION *MenuOption,
- IN CHAR16 *OptionString
- )
-{
- UINTN Index;
- UINT16 Width;
- UINTN Row;
- CHAR16 *OutputString;
- UINT16 GlyphWidth;
-
- Width = (UINT16)gOptionBlockWidth - 1;
- GlyphWidth = 1;
- Row = 1;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
- if (StrLen (&OptionString[Index]) != 0) {
- Row++;
- }
-
- FreePool (OutputString);
- }
-
- if ((Row > MenuOption->Skip) &&
- (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) &&
- (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP))
- {
- MenuOption->Skip = Row;
- }
-}
-
-/**
- Update display lines for a Menu Option.
-
- @param MenuOption The MenuOption to be checked.
-
-**/
-VOID
-UpdateOptionSkipLines (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- CHAR16 *OptionString;
-
- OptionString = NULL;
-
- ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
- if (OptionString != NULL) {
- UpdateSkipInfoForMenu (MenuOption, OptionString);
-
- FreePool (OptionString);
- }
-
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
- OptionString = GetToken (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
-
- if (OptionString != NULL) {
- UpdateSkipInfoForMenu (MenuOption, OptionString);
-
- FreePool (OptionString);
- }
- }
-}
-
-/**
- Check whether this Menu Option could be print.
-
- Check Prompt string, option string or text two string not NULL.
-
- This is an internal function.
-
- @param MenuOption The MenuOption to be checked.
-
- @retval TRUE This Menu Option is printable.
- @retval FALSE This Menu Option could not be printable.
-
-**/
-BOOLEAN
-PrintableMenu (
- UI_MENU_OPTION *MenuOption
- )
-{
- EFI_STATUS Status;
- EFI_STRING OptionString;
-
- OptionString = NULL;
-
- if (MenuOption->Description[0] != '\0') {
- return TRUE;
- }
-
- Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- if ((OptionString != NULL) && (OptionString[0] != '\0')) {
- FreePool (OptionString);
- return TRUE;
- }
-
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
- OptionString = GetToken (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
- ASSERT (OptionString != NULL);
- if (OptionString[0] != '\0') {
- FreePool (OptionString);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Check whether this Menu Option could be highlighted.
-
- This is an internal function.
-
- @param MenuOption The MenuOption to be checked.
-
- @retval TRUE This Menu Option is selectable.
- @retval FALSE This Menu Option could not be selected.
-
-**/
-BOOLEAN
-IsSelectable (
- UI_MENU_OPTION *MenuOption
- )
-{
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
- MenuOption->GrayOut || MenuOption->ReadOnly || !PrintableMenu (MenuOption))
- {
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-/**
- Move to next selectable statement.
-
- This is an internal function.
-
- @param GoUp The navigation direction. TRUE: up, FALSE: down.
- @param CurrentPosition Current position.
- @param GapToTop Gap position to top or bottom.
- @param FindInForm Whether find menu in current form or beyond.
-
- @return The row distance from current MenuOption to next selectable MenuOption.
-
- @retval -1 Reach the begin of the menu, still can't find the selectable menu.
- @retval Value Find the selectable menu, maybe the truly selectable, maybe the
- first menu showing beyond current form or last menu showing in
- current form.
- The value is the line number between the new selected menu and the
- current select menu, not include the new selected menu.
-
-**/
-INTN
-MoveToNextStatement (
- IN BOOLEAN GoUp,
- IN OUT LIST_ENTRY **CurrentPosition,
- IN UINTN GapToTop,
- IN BOOLEAN FindInForm
- )
-{
- INTN Distance;
- LIST_ENTRY *Pos;
- UI_MENU_OPTION *NextMenuOption;
- UI_MENU_OPTION *PreMenuOption;
-
- Distance = 0;
- Pos = *CurrentPosition;
-
- if (Pos == &gMenuOption) {
- return -1;
- }
-
- PreMenuOption = MENU_OPTION_FROM_LINK (Pos);
-
- while (TRUE) {
- NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
- //
- // NextMenuOption->Row == 0 means this menu has not calculate
- // the NextMenuOption->Skip value yet, just calculate here.
- //
- if (NextMenuOption->Row == 0) {
- UpdateOptionSkipLines (NextMenuOption);
- }
-
- //
- // Check whether the menu is beyond current showing form,
- // return the first one beyond the showing form.
- //
- if ((UINTN)Distance + NextMenuOption->Skip > GapToTop) {
- if (FindInForm) {
- NextMenuOption = PreMenuOption;
- }
-
- break;
- }
-
- //
- // return the selectable menu in the showing form.
- //
- if (IsSelectable (NextMenuOption)) {
- break;
- }
-
- Distance += NextMenuOption->Skip;
-
- //
- // Arrive at begin of the menu list.
- //
- if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {
- Distance = -1;
- break;
- }
-
- Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
- PreMenuOption = NextMenuOption;
- }
-
- *CurrentPosition = &NextMenuOption->Link;
- return Distance;
-}
-
-/**
- Process option string for date/time opcode.
-
- @param MenuOption Menu option point to date/time.
- @param OptionString Option string input for process.
- @param AddOptCol Whether need to update MenuOption->OptCol.
-
-**/
-VOID
-ProcessStringForDateTime (
- UI_MENU_OPTION *MenuOption,
- CHAR16 *OptionString,
- BOOLEAN AddOptCol
- )
-{
- UINTN Index;
- UINTN Count;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- EFI_IFR_DATE *Date;
- EFI_IFR_TIME *Time;
-
- ASSERT (MenuOption != NULL && OptionString != NULL);
-
- Statement = MenuOption->ThisTag;
- Date = NULL;
- Time = NULL;
- if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
- Date = (EFI_IFR_DATE *)Statement->OpCode;
- } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
- Time = (EFI_IFR_TIME *)Statement->OpCode;
- }
-
- //
- // If leading spaces on OptionString - remove the spaces
- //
- for (Index = 0; OptionString[Index] == L' '; Index++) {
- //
- // Base on the blockspace to get the option column info.
- //
- if (AddOptCol) {
- MenuOption->OptCol++;
- }
- }
-
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
- OptionString[Count] = OptionString[Index];
- Count++;
- }
-
- OptionString[Count] = CHAR_NULL;
-
- //
- // Enable to suppress field in the opcode base on the flag.
- //
- if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
- //
- // OptionString format is: <**: **: ****>
- // |month|day|year|
- // 4 3 5
- //
- if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {
- //
- // At this point, only "<**:" in the optionstring.
- // Clean the day's ** field, after clean, the format is "< :"
- //
- SetUnicodeMem (&OptionString[1], 2, L' ');
- } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {
- //
- // At this point, only "**:" in the optionstring.
- // Clean the month's "**" field, after clean, the format is " :"
- //
- SetUnicodeMem (&OptionString[0], 2, L' ');
- } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {
- //
- // At this point, only "****>" in the optionstring.
- // Clean the year's "****" field, after clean, the format is " >"
- //
- SetUnicodeMem (&OptionString[0], 4, L' ');
- }
- } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
- //
- // OptionString format is: <**: **: **>
- // |hour|minute|second|
- // 4 3 3
- //
- if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {
- //
- // At this point, only "<**:" in the optionstring.
- // Clean the hour's ** field, after clean, the format is "< :"
- //
- SetUnicodeMem (&OptionString[1], 2, L' ');
- } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {
- //
- // At this point, only "**:" in the optionstring.
- // Clean the minute's "**" field, after clean, the format is " :"
- //
- SetUnicodeMem (&OptionString[0], 2, L' ');
- } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {
- //
- // At this point, only "**>" in the optionstring.
- // Clean the second's "**" field, after clean, the format is " >"
- //
- SetUnicodeMem (&OptionString[0], 2, L' ');
- }
- }
-}
-
-/**
- Adjust Data and Time position accordingly.
- Data format : [01/02/2004] [11:22:33]
- Line number : 0 0 1 0 0 1
-
- This is an internal function.
-
- @param DirectionUp the up or down direction. False is down. True is
- up.
- @param CurrentPosition Current position. On return: Point to the last
- Option (Year or Second) if up; Point to the first
- Option (Month or Hour) if down.
-
- @return Return line number to pad. It is possible that we stand on a zero-advance
- @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
-
-**/
-UINTN
-AdjustDateAndTimePosition (
- IN BOOLEAN DirectionUp,
- IN OUT LIST_ENTRY **CurrentPosition
- )
-{
- UINTN Count;
- LIST_ENTRY *NewPosition;
- UI_MENU_OPTION *MenuOption;
- UINTN PadLineNumber;
-
- PadLineNumber = 0;
- NewPosition = *CurrentPosition;
- MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
-
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||
- (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP))
- {
- //
- // Calculate the distance from current position to the last Date/Time MenuOption
- //
- Count = 0;
- while (MenuOption->Skip == 0) {
- Count++;
- NewPosition = NewPosition->ForwardLink;
- MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
- PadLineNumber = 1;
- }
-
- NewPosition = *CurrentPosition;
- if (DirectionUp) {
- //
- // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
- // to be one that back to the previous set of MenuOptions, we need to advance to the first
- // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
- // checking can be done.
- //
- while (Count++ < 2) {
- NewPosition = NewPosition->BackLink;
- }
- } else {
- //
- // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
- // to be one that progresses to the next set of MenuOptions, we need to advance to the last
- // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
- // checking can be done.
- //
- while (Count-- > 0) {
- NewPosition = NewPosition->ForwardLink;
- }
- }
-
- *CurrentPosition = NewPosition;
- }
-
- return PadLineNumber;
-}
-
-/**
- Get step info from numeric opcode.
-
- @param[in] OpCode The input numeric op code.
-
- @return step info for this opcode.
-**/
-UINT64
-GetFieldFromNum (
- IN EFI_IFR_OP_HEADER *OpCode
- )
-{
- EFI_IFR_NUMERIC *NumericOp;
- UINT64 Step;
-
- NumericOp = (EFI_IFR_NUMERIC *)OpCode;
-
- switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
- case EFI_IFR_NUMERIC_SIZE_1:
- Step = NumericOp->data.u8.Step;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_2:
- Step = NumericOp->data.u16.Step;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_4:
- Step = NumericOp->data.u32.Step;
- break;
-
- case EFI_IFR_NUMERIC_SIZE_8:
- Step = NumericOp->data.u64.Step;
- break;
-
- default:
- Step = 0;
- break;
- }
-
- return Step;
-}
-
-/**
- Find the registered HotKey based on KeyData.
-
- @param[in] KeyData A pointer to a buffer that describes the keystroke
- information for the hot key.
-
- @return The registered HotKey context. If no found, NULL will return.
-**/
-BROWSER_HOT_KEY *
-GetHotKeyFromRegisterList (
- IN EFI_INPUT_KEY *KeyData
- )
-{
- LIST_ENTRY *Link;
- BROWSER_HOT_KEY *HotKey;
-
- Link = GetFirstNode (&gFormData->HotKeyListHead);
- while (!IsNull (&gFormData->HotKeyListHead, Link)) {
- HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
-
- if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
- return HotKey;
- }
-
- Link = GetNextNode (&gFormData->HotKeyListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Determine if the menu is the last menu that can be selected.
-
- This is an internal function.
-
- @param Direction The scroll direction. False is down. True is up.
- @param CurrentPos The current focus.
-
- @return FALSE -- the menu isn't the last menu that can be selected.
- @return TRUE -- the menu is the last menu that can be selected.
-
-**/
-BOOLEAN
-ValueIsScroll (
- IN BOOLEAN Direction,
- IN LIST_ENTRY *CurrentPos
- )
-{
- LIST_ENTRY *Temp;
-
- Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
-
- if (Temp == &gMenuOption) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Wait for a given event to fire, or for an optional timeout to expire.
-
- @param Event The event to wait for
-
- @retval UI_EVENT_TYPE The type of the event which is trigged.
-
-**/
-UI_EVENT_TYPE
-UiWaitForEvent (
- IN EFI_EVENT Event
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINTN EventNum;
- UINT64 Timeout;
- EFI_EVENT TimerEvent;
- EFI_EVENT WaitList[3];
- UI_EVENT_TYPE EventType;
-
- TimerEvent = NULL;
- Timeout = FormExitTimeout (gFormData);
-
- if (Timeout != 0) {
- Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
-
- //
- // Set the timer event
- //
- gBS->SetTimer (
- TimerEvent,
- TimerRelative,
- Timeout
- );
- }
-
- WaitList[0] = Event;
- EventNum = 1;
- if (gFormData->FormRefreshEvent != NULL) {
- WaitList[EventNum] = gFormData->FormRefreshEvent;
- EventNum++;
- }
-
- if (Timeout != 0) {
- WaitList[EventNum] = TimerEvent;
- EventNum++;
- }
-
- Status = gBS->WaitForEvent (EventNum, WaitList, &Index);
- ASSERT_EFI_ERROR (Status);
-
- switch (Index) {
- case 0:
- EventType = UIEventKey;
- break;
-
- case 1:
- if (gFormData->FormRefreshEvent != NULL) {
- EventType = UIEventDriver;
- } else {
- ASSERT (Timeout != 0 && EventNum == 2);
- EventType = UIEventTimeOut;
- }
-
- break;
-
- default:
- ASSERT (Index == 2 && EventNum == 3);
- EventType = UIEventTimeOut;
- break;
- }
-
- if (Timeout != 0) {
- gBS->CloseEvent (TimerEvent);
- }
-
- return EventType;
-}
-
-/**
- Get question id info from the input opcode header.
-
- @param OpCode The input opcode header pointer.
-
- @retval The question id for this opcode.
-
-**/
-EFI_QUESTION_ID
-GetQuestionIdInfo (
- IN EFI_IFR_OP_HEADER *OpCode
- )
-{
- EFI_IFR_QUESTION_HEADER *QuestionHeader;
-
- if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {
- return 0;
- }
-
- QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *)OpCode + sizeof (EFI_IFR_OP_HEADER));
-
- return QuestionHeader->QuestionId;
-}
-
-/**
- Find the top of screen menu base on the current menu.
-
- @param CurPos Current input menu.
- @param Rows Totol screen rows.
- @param SkipValue SkipValue for this new form.
-
- @retval TopOfScreen Top of screen menu for the new form.
-
-**/
-LIST_ENTRY *
-FindTopOfScreenMenu (
- IN LIST_ENTRY *CurPos,
- IN UINTN Rows,
- OUT UINTN *SkipValue
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *TopOfScreen;
- UI_MENU_OPTION *PreviousMenuOption;
-
- Link = CurPos;
- PreviousMenuOption = NULL;
-
- while (Link->BackLink != &gMenuOption) {
- Link = Link->BackLink;
- PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
- if (PreviousMenuOption->Row == 0) {
- UpdateOptionSkipLines (PreviousMenuOption);
- }
-
- if (Rows <= PreviousMenuOption->Skip) {
- break;
- }
-
- Rows = Rows - PreviousMenuOption->Skip;
- }
-
- if (Link->BackLink == &gMenuOption) {
- TopOfScreen = gMenuOption.ForwardLink;
- if ((PreviousMenuOption != NULL) && (Rows < PreviousMenuOption->Skip)) {
- *SkipValue = PreviousMenuOption->Skip - Rows;
- } else {
- *SkipValue = 0;
- }
- } else {
- TopOfScreen = Link;
- *SkipValue = PreviousMenuOption->Skip - Rows;
- }
-
- return TopOfScreen;
-}
-
-/**
- Get the index info for this opcode.
-
- @param OpCode The input opcode for the statement.
-
- @retval The index of this statement.
-
-**/
-UINTN
-GetIndexInfoForOpcode (
- IN EFI_IFR_OP_HEADER *OpCode
- )
-{
- LIST_ENTRY *NewPos;
- UI_MENU_OPTION *MenuOption;
- UINTN Index;
-
- NewPos = gMenuOption.ForwardLink;
- Index = 0;
-
- for (NewPos = gMenuOption.ForwardLink; NewPos != &gMenuOption; NewPos = NewPos->ForwardLink) {
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- if (CompareMem (MenuOption->ThisTag->OpCode, OpCode, OpCode->Length) == 0) {
- if (MenuOption->ThisTag->OpCode == OpCode) {
- return Index;
- }
-
- Index++;
- }
- }
-
- return Index;
-}
-
-/**
- Is this the saved highlight statement.
-
- @param HighLightedStatement The input highlight statement.
-
- @retval TRUE This is the highlight statement.
- @retval FALSE This is not the highlight statement.
-
-**/
-BOOLEAN
-IsSavedHighlightStatement (
- IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
- )
-{
- if ((gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) &&
- (gFormData->FormId == gHighligthMenuInfo.FormId))
- {
- if (gHighligthMenuInfo.HLTQuestionId != 0) {
- return (BOOLEAN)(gHighligthMenuInfo.HLTQuestionId == GetQuestionIdInfo (HighLightedStatement->OpCode));
- } else {
- if (CompareMem (gHighligthMenuInfo.HLTOpCode, HighLightedStatement->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
- if ((gHighligthMenuInfo.HLTIndex == 0) || (gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode (HighLightedStatement->OpCode))) {
- return TRUE;
- } else {
- return FALSE;
- }
- }
- }
- }
-
- return FALSE;
-}
-
-/**
- Is this the highlight menu.
-
- @param MenuOption The input Menu option.
-
- @retval TRUE This is the highlight menu option.
- @retval FALSE This is not the highlight menu option.
-
-**/
-BOOLEAN
-IsHighLightMenuOption (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- if (gHighligthMenuInfo.HLTQuestionId != 0) {
- if (GetQuestionIdInfo (MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.HLTQuestionId) {
- return (BOOLEAN)(MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
- }
- } else {
- if (CompareMem (gHighligthMenuInfo.HLTOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
- if ((gHighligthMenuInfo.HLTIndex == 0) || (gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode (MenuOption->ThisTag->OpCode))) {
- return (BOOLEAN)(MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
- } else {
- return FALSE;
- }
- }
- }
-
- return FALSE;
-}
-
-/**
- Find the highlight menu.
-
- If the input is NULL, base on the record highlight info in
- gHighligthMenuInfo to find the last highlight menu.
-
- @param HighLightedStatement The input highlight statement.
-
- @retval The highlight menu index.
-
-**/
-LIST_ENTRY *
-FindHighLightMenuOption (
- IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
- )
-{
- LIST_ENTRY *NewPos;
- UI_MENU_OPTION *MenuOption;
-
- NewPos = gMenuOption.ForwardLink;
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- if (HighLightedStatement != NULL) {
- while (MenuOption->ThisTag != HighLightedStatement) {
- NewPos = NewPos->ForwardLink;
- if (NewPos == &gMenuOption) {
- //
- // Not Found it, break
- //
- break;
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- }
-
- //
- // Must find the highlight statement.
- //
- ASSERT (NewPos != &gMenuOption);
- } else {
- while (!IsHighLightMenuOption (MenuOption)) {
- NewPos = NewPos->ForwardLink;
- if (NewPos == &gMenuOption) {
- //
- // Not Found it, break
- //
- break;
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- }
-
- //
- // Highlight statement has disappear (suppressed/disableed)
- //
- if (NewPos == &gMenuOption) {
- NewPos = NULL;
- }
- }
-
- return NewPos;
-}
-
-/**
- Is this the Top of screen menu.
-
- @param MenuOption The input Menu option.
-
- @retval TRUE This is the Top of screen menu option.
- @retval FALSE This is not the Top of screen menu option.
-
-**/
-BOOLEAN
-IsTopOfScreeMenuOption (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- if (gHighligthMenuInfo.TOSQuestionId != 0) {
- return (BOOLEAN)(GetQuestionIdInfo (MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.TOSQuestionId);
- }
-
- if (CompareMem (gHighligthMenuInfo.TOSOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.TOSOpCode->Length) == 0) {
- if ((gHighligthMenuInfo.TOSIndex == 0) || (gHighligthMenuInfo.TOSIndex == GetIndexInfoForOpcode (MenuOption->ThisTag->OpCode))) {
- return TRUE;
- } else {
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Calculate the distance between two menus and include the skip value of StartMenu.
-
- @param StartMenu The link_entry pointer to start menu.
- @param EndMenu The link_entry pointer to end menu.
-
-**/
-UINTN
-GetDistanceBetweenMenus (
- IN LIST_ENTRY *StartMenu,
- IN LIST_ENTRY *EndMenu
- )
-{
- LIST_ENTRY *Link;
- UI_MENU_OPTION *MenuOption;
- UINTN Distance;
-
- Distance = 0;
-
- Link = StartMenu;
- while (Link != EndMenu) {
- MenuOption = MENU_OPTION_FROM_LINK (Link);
- if (MenuOption->Row == 0) {
- UpdateOptionSkipLines (MenuOption);
- }
-
- Distance += MenuOption->Skip;
- Link = Link->BackLink;
- }
-
- return Distance;
-}
-
-/**
- Find the top of screen menu base on the previous record menu info.
-
- @param HighLightMenu The link_entry pointer to highlight menu.
-
- @retval Return the the link_entry pointer top of screen menu.
-
-**/
-LIST_ENTRY *
-FindTopOfScreenMenuOption (
- IN LIST_ENTRY *HighLightMenu
- )
-{
- LIST_ENTRY *NewPos;
- UI_MENU_OPTION *MenuOption;
- UINTN TopRow;
- UINTN BottomRow;
-
- TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
- BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
-
- NewPos = gMenuOption.ForwardLink;
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- while (!IsTopOfScreeMenuOption (MenuOption)) {
- NewPos = NewPos->ForwardLink;
- if (NewPos == &gMenuOption) {
- //
- // Not Found it, break
- //
- break;
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- }
-
- //
- // Last time top of screen menu has disappeared.
- //
- if (NewPos == &gMenuOption) {
- return NULL;
- }
-
- //
- // Check whether highlight menu and top of screen menu can be shown within one page,
- // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
- // may be dynamically inserted between highlightmenu and previous top of screen menu,
- // So previous record top of screen menu is not appropriate for current display.
- //
- if (GetDistanceBetweenMenus (HighLightMenu, NewPos) + 1 > BottomRow - TopRow) {
- return NULL;
- }
-
- return NewPos;
-}
-
-/**
- Find the first menu which will be show at the top.
-
- @param FormData The data info for this form.
- @param TopOfScreen The link_entry pointer to top menu.
- @param HighlightMenu The menu which will be highlight.
- @param SkipValue The skip value for the top menu.
-
-**/
-VOID
-FindTopMenu (
- IN FORM_DISPLAY_ENGINE_FORM *FormData,
- OUT LIST_ENTRY **TopOfScreen,
- OUT LIST_ENTRY **HighlightMenu,
- OUT UINTN *SkipValue
- )
-{
- UINTN TopRow;
- UINTN BottomRow;
- UI_MENU_OPTION *MenuOption;
- UINTN TmpValue;
-
- TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
- BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
- //
- // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
- // and the other is exit current form and enter last form, it can be covered by the else case.
- //
- if (gMisMatch && (gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) && (gFormData->FormId == gHighligthMenuInfo.FormId)) {
- //
- // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
- // base on the record highlight info to find the highlight menu.
- //
-
- *HighlightMenu = FindHighLightMenuOption (NULL);
- if (*HighlightMenu != NULL) {
- //
- // Update skip info for this highlight menu.
- //
- MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
- UpdateOptionSkipLines (MenuOption);
-
- //
- // Found the last time highlight menu.
- //
- *TopOfScreen = FindTopOfScreenMenuOption (*HighlightMenu);
- if (*TopOfScreen != NULL) {
- //
- // Found the last time selectable top of screen menu.
- //
- AdjustDateAndTimePosition (TRUE, TopOfScreen);
- MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
- UpdateOptionSkipLines (MenuOption);
-
- *SkipValue = gHighligthMenuInfo.SkipValue;
- } else {
- //
- // Not found last time top of screen menu, so base on current highlight menu
- // to find the new top of screen menu.
- // Make the current highlight menu at the bottom of the form to calculate the
- // top of screen menu.
- //
- if (MenuOption->Skip >= BottomRow - TopRow) {
- *TopOfScreen = *HighlightMenu;
- TmpValue = 0;
- } else {
- *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
- }
-
- *SkipValue = TmpValue;
- }
- } else {
- //
- // Last time highlight menu has disappear, find the first highlightable menu as the default one.
- //
- *HighlightMenu = gMenuOption.ForwardLink;
- if (!IsListEmpty (&gMenuOption)) {
- MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
- }
-
- *TopOfScreen = gMenuOption.ForwardLink;
- *SkipValue = 0;
- }
- } else if (FormData->HighLightedStatement != NULL) {
- if (IsSavedHighlightStatement (FormData->HighLightedStatement)) {
- //
- // Input highlight menu is same as last time highlight menu.
- // Base on last time highlight menu to set the top of screen menu and highlight menu.
- //
- *HighlightMenu = FindHighLightMenuOption (NULL);
- ASSERT (*HighlightMenu != NULL);
-
- //
- // Update skip info for this highlight menu.
- //
- MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
- UpdateOptionSkipLines (MenuOption);
-
- *TopOfScreen = FindTopOfScreenMenuOption (*HighlightMenu);
- if (*TopOfScreen == NULL) {
- //
- // Not found last time top of screen menu, so base on current highlight menu
- // to find the new top of screen menu.
- // Make the current highlight menu at the bottom of the form to calculate the
- // top of screen menu.
- //
- if (MenuOption->Skip >= BottomRow - TopRow) {
- *TopOfScreen = *HighlightMenu;
- TmpValue = 0;
- } else {
- *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
- }
-
- *SkipValue = TmpValue;
- } else {
- AdjustDateAndTimePosition (TRUE, TopOfScreen);
- MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
- UpdateOptionSkipLines (MenuOption);
-
- *SkipValue = gHighligthMenuInfo.SkipValue;
- }
-
- AdjustDateAndTimePosition (TRUE, TopOfScreen);
- } else {
- //
- // Input highlight menu is not save as last time highlight menu.
- //
- *HighlightMenu = FindHighLightMenuOption (FormData->HighLightedStatement);
- MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
- UpdateOptionSkipLines (MenuOption);
-
- //
- // Make the current highlight menu at the bottom of the form to calculate the
- // top of screen menu.
- //
- if (MenuOption->Skip >= BottomRow - TopRow) {
- *TopOfScreen = *HighlightMenu;
- TmpValue = 0;
- } else {
- *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
- }
-
- *SkipValue = TmpValue;
- }
-
- AdjustDateAndTimePosition (TRUE, TopOfScreen);
- } else {
- //
- // If not has input highlight statement, just return the first one in this form.
- //
- *TopOfScreen = gMenuOption.ForwardLink;
- *HighlightMenu = gMenuOption.ForwardLink;
- if (!IsListEmpty (&gMenuOption)) {
- MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
- }
-
- *SkipValue = 0;
- }
-
- gMisMatch = FALSE;
-
- //
- // First enter to show the menu, update highlight info.
- //
- UpdateHighlightMenuInfo (*HighlightMenu, *TopOfScreen, *SkipValue);
-}
-
-/**
- Record the highlight menu and top of screen menu info.
-
- @param Highlight The menu opton which is highlight.
- @param TopOfScreen The menu opton which is at the top of the form.
- @param SkipValue The skip line info for the top of screen menu.
-
-**/
-VOID
-UpdateHighlightMenuInfo (
- IN LIST_ENTRY *Highlight,
- IN LIST_ENTRY *TopOfScreen,
- IN UINTN SkipValue
- )
-{
- UI_MENU_OPTION *MenuOption;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
-
- gHighligthMenuInfo.HiiHandle = gFormData->HiiHandle;
- gHighligthMenuInfo.FormId = gFormData->FormId;
- gHighligthMenuInfo.SkipValue = (UINT16)SkipValue;
-
- if (!IsListEmpty (&gMenuOption)) {
- MenuOption = MENU_OPTION_FROM_LINK (Highlight);
- Statement = MenuOption->ThisTag;
-
- gUserInput->SelectedStatement = Statement;
-
- gHighligthMenuInfo.HLTSequence = MenuOption->Sequence;
- gHighligthMenuInfo.HLTQuestionId = GetQuestionIdInfo (Statement->OpCode);
- if (gHighligthMenuInfo.HLTQuestionId == 0) {
- //
- // if question id == 0, save the opcode buffer..
- //
- if (gHighligthMenuInfo.HLTOpCode != NULL) {
- FreePool (gHighligthMenuInfo.HLTOpCode);
- }
-
- gHighligthMenuInfo.HLTOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
- ASSERT (gHighligthMenuInfo.HLTOpCode != NULL);
-
- gHighligthMenuInfo.HLTIndex = GetIndexInfoForOpcode (Statement->OpCode);
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
- Statement = MenuOption->ThisTag;
-
- gHighligthMenuInfo.TOSQuestionId = GetQuestionIdInfo (Statement->OpCode);
- if (gHighligthMenuInfo.TOSQuestionId == 0) {
- //
- // if question id == 0, save the opcode buffer..
- //
- if (gHighligthMenuInfo.TOSOpCode != NULL) {
- FreePool (gHighligthMenuInfo.TOSOpCode);
- }
-
- gHighligthMenuInfo.TOSOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
- ASSERT (gHighligthMenuInfo.TOSOpCode != NULL);
-
- gHighligthMenuInfo.TOSIndex = GetIndexInfoForOpcode (Statement->OpCode);
- }
- } else {
- gUserInput->SelectedStatement = NULL;
-
- gHighligthMenuInfo.HLTSequence = 0;
- gHighligthMenuInfo.HLTQuestionId = 0;
- if (gHighligthMenuInfo.HLTOpCode != NULL) {
- FreePool (gHighligthMenuInfo.HLTOpCode);
- }
-
- gHighligthMenuInfo.HLTOpCode = NULL;
- gHighligthMenuInfo.HLTIndex = 0;
-
- gHighligthMenuInfo.TOSQuestionId = 0;
- if (gHighligthMenuInfo.TOSOpCode != NULL) {
- FreePool (gHighligthMenuInfo.TOSOpCode);
- }
-
- gHighligthMenuInfo.TOSOpCode = NULL;
- gHighligthMenuInfo.TOSIndex = 0;
- }
-}
-
-/**
- Update attribut for this menu.
-
- @param MenuOption The menu opton which this attribut used to.
- @param Highlight Whether this menu will be highlight.
-
-**/
-VOID
-SetDisplayAttribute (
- IN UI_MENU_OPTION *MenuOption,
- IN BOOLEAN Highlight
- )
-{
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
-
- Statement = MenuOption->ThisTag;
-
- if (Highlight) {
- gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
- return;
- }
-
- if (MenuOption->GrayOut) {
- gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
- } else {
- if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
- gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
- } else {
- gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
- }
- }
-}
-
-/**
- Print string for this menu option.
-
- @param MenuOption The menu opton which this attribut used to.
- @param Col The column that this string will be print at.
- @param Row The row that this string will be print at.
- @param String The string which need to print.
- @param Width The width need to print, if string is less than the
- width, the block space will be used.
- @param Highlight Whether this menu will be highlight.
-
-**/
-VOID
-DisplayMenuString (
- IN UI_MENU_OPTION *MenuOption,
- IN UINTN Col,
- IN UINTN Row,
- IN CHAR16 *String,
- IN UINTN Width,
- IN BOOLEAN Highlight
- )
-{
- UINTN Length;
-
- //
- // Print string with normal color.
- //
- if (!Highlight) {
- PrintStringAtWithWidth (Col, Row, String, Width);
- return;
- }
-
- //
- // Print the highlight menu string.
- // First print the highlight string.
- //
- SetDisplayAttribute (MenuOption, TRUE);
- Length = PrintStringAt (Col, Row, String);
-
- //
- // Second, clean the empty after the string.
- //
- SetDisplayAttribute (MenuOption, FALSE);
- PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);
-}
-
-/**
- Check whether this menu can has option string.
-
- @param MenuOption The menu opton which this attribut used to.
-
- @retval TRUE This menu option can have option string.
- @retval FALSE This menu option can't have option string.
-
-**/
-BOOLEAN
-HasOptionString (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- CHAR16 *String;
- UINTN Size;
- EFI_IFR_TEXT *TextOp;
-
- Size = 0;
- Statement = MenuOption->ThisTag;
-
- //
- // See if the second text parameter is really NULL
- //
- if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
- TextOp = (EFI_IFR_TEXT *)Statement->OpCode;
- if (TextOp->TextTwo != 0) {
- String = GetToken (TextOp->TextTwo, gFormData->HiiHandle);
- Size = StrLen (String);
- FreePool (String);
- }
- }
-
- if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
- (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
- //
- // Allow a wide display if text op-code and no secondary text op-code
- //
- ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
- )
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Double confirm with user about the action.
-
- @param Action The user input action.
-
- @retval TRUE User confirm with the input or not need user confirm.
- @retval FALSE User want ignore this input.
-
-**/
-BOOLEAN
-FxConfirmPopup (
- IN UINT32 Action
- )
-{
- EFI_INPUT_KEY Key;
- CHAR16 *CfmStr;
- UINTN CfmStrLen;
- UINT32 CheckFlags;
- BOOLEAN RetVal;
- UINTN CatLen;
- UINTN MaxLen;
-
- CfmStrLen = 0;
- CatLen = StrLen (gConfirmMsgConnect);
-
- //
- // Below action need extra popup dialog to confirm.
- //
- CheckFlags = BROWSER_ACTION_DISCARD |
- BROWSER_ACTION_DEFAULT |
- BROWSER_ACTION_SUBMIT |
- BROWSER_ACTION_RESET |
- BROWSER_ACTION_EXIT;
-
- //
- // Not need to confirm with user, just return TRUE.
- //
- if ((Action & CheckFlags) == 0) {
- return TRUE;
- }
-
- if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
- CfmStrLen += StrLen (gConfirmDiscardMsg);
- }
-
- if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
- if (CfmStrLen != 0) {
- CfmStrLen += CatLen;
- }
-
- CfmStrLen += StrLen (gConfirmDefaultMsg);
- }
-
- if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
- if (CfmStrLen != 0) {
- CfmStrLen += CatLen;
- }
-
- CfmStrLen += StrLen (gConfirmSubmitMsg);
- }
-
- if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
- if (CfmStrLen != 0) {
- CfmStrLen += CatLen;
- }
-
- CfmStrLen += StrLen (gConfirmResetMsg);
- }
-
- if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
- if (CfmStrLen != 0) {
- CfmStrLen += CatLen;
- }
-
- CfmStrLen += StrLen (gConfirmExitMsg);
- }
-
- //
- // Allocate buffer to save the string.
- // String + "?" + "\0"
- //
- MaxLen = CfmStrLen + 1 + 1;
- CfmStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (CfmStr != NULL);
-
- if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
- StrCpyS (CfmStr, MaxLen, gConfirmDiscardMsg);
- }
-
- if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
- if (CfmStr[0] != 0) {
- StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
- StrCatS (CfmStr, MaxLen, gConfirmDefaultMsg2nd);
- } else {
- StrCpyS (CfmStr, MaxLen, gConfirmDefaultMsg);
- }
- }
-
- if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
- if (CfmStr[0] != 0) {
- StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
- StrCatS (CfmStr, MaxLen, gConfirmSubmitMsg2nd);
- } else {
- StrCpyS (CfmStr, MaxLen, gConfirmSubmitMsg);
- }
- }
-
- if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
- if (CfmStr[0] != 0) {
- StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
- StrCatS (CfmStr, MaxLen, gConfirmResetMsg2nd);
- } else {
- StrCpyS (CfmStr, MaxLen, gConfirmResetMsg);
- }
- }
-
- if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
- if (CfmStr[0] != 0) {
- StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
- StrCatS (CfmStr, MaxLen, gConfirmExitMsg2nd);
- } else {
- StrCpyS (CfmStr, MaxLen, gConfirmExitMsg);
- }
- }
-
- StrCatS (CfmStr, MaxLen, gConfirmMsgEnd);
-
- do {
- CreateDialog (&Key, gEmptyString, CfmStr, gConfirmOpt, gEmptyString, NULL);
- } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptNo[0] | UPPER_LOWER_CASE_OFFSET)) &&
- (Key.ScanCode != SCAN_ESC));
-
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) {
- RetVal = TRUE;
- } else {
- RetVal = FALSE;
- }
-
- FreePool (CfmStr);
-
- return RetVal;
-}
-
-/**
- Print string for this menu option.
-
- @param MenuOption The menu opton which this attribut used to.
- @param SkipWidth The skip width between the left to the start of the prompt.
- @param BeginCol The begin column for one menu.
- @param SkipLine The skip line for this menu.
- @param BottomRow The bottom row for this form.
- @param Highlight Whether this menu will be highlight.
- @param UpdateCol Whether need to update the column info for Date/Time.
-
- @retval EFI_SUCESSS Process the user selection success.
-
-**/
-EFI_STATUS
-DisplayOneMenu (
- IN UI_MENU_OPTION *MenuOption,
- IN UINTN SkipWidth,
- IN UINTN BeginCol,
- IN UINTN SkipLine,
- IN UINTN BottomRow,
- IN BOOLEAN Highlight,
- IN BOOLEAN UpdateCol
- )
-{
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- UINTN Index;
- UINT16 Width;
- UINT16 PromptWidth;
- CHAR16 *StringPtr;
- CHAR16 *OptionString;
- CHAR16 *OutputString;
- UINT16 GlyphWidth;
- UINTN Temp;
- UINTN Temp2;
- UINTN Temp3;
- EFI_STATUS Status;
- UINTN Row;
- BOOLEAN IsProcessingFirstRow;
- UINTN Col;
- UINTN PromptLineNum;
- UINTN OptionLineNum;
- CHAR16 AdjustValue;
- UINTN MaxRow;
-
- Statement = MenuOption->ThisTag;
- Temp = SkipLine;
- Temp2 = SkipLine;
- Temp3 = SkipLine;
- AdjustValue = 0;
- PromptLineNum = 0;
- OptionLineNum = 0;
- MaxRow = 0;
- IsProcessingFirstRow = TRUE;
-
- //
- // Set default color.
- //
- SetDisplayAttribute (MenuOption, FALSE);
-
- //
- // 1. Paint the option string.
- //
- Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (OptionString != NULL) {
- if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- //
- // Adjust option string for date/time opcode.
- //
- ProcessStringForDateTime (MenuOption, OptionString, UpdateCol);
- }
-
- Width = (UINT16)gOptionBlockWidth - 1;
- Row = MenuOption->Row;
- GlyphWidth = 1;
- OptionLineNum = 0;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
- if (((Temp2 == 0)) && (Row <= BottomRow)) {
- if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- //
- // For date/time question, it has three menu options for this qustion.
- // The first/second menu options with the skip value is 0. the last one
- // with skip value is 1.
- //
- if (MenuOption->Skip != 0) {
- //
- // For date/ time, print the last past (year for date and second for time)
- // - 7 means skip [##/##/ for date and [##:##: for time.
- //
- DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);
- } else {
- //
- // For date/ time, print the first and second past (year for date and second for time)
- // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
- // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
- DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString) - 1, Highlight);
- }
- } else {
- DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
- }
-
- OptionLineNum++;
- }
-
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&OptionString[Index]) != 0) {
- if (Temp2 == 0) {
- Row++;
- //
- // Since the Number of lines for this menu entry may or may not be reflected accurately
- // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
- // some testing to ensure we are keeping this in-sync.
- //
- // If the difference in rows is greater than or equal to the skip value, increase the skip value
- //
- if ((Row - MenuOption->Row) >= MenuOption->Skip) {
- MenuOption->Skip++;
- }
- }
- }
-
- FreePool (OutputString);
- if (Temp2 != 0) {
- Temp2--;
- }
- }
-
- Highlight = FALSE;
-
- FreePool (OptionString);
- }
-
- //
- // 2. Paint the description.
- //
- PromptWidth = GetWidth (MenuOption, &AdjustValue);
- Row = MenuOption->Row;
- GlyphWidth = 1;
- PromptLineNum = 0;
-
- if ((MenuOption->Description == NULL) || (MenuOption->Description[0] == '\0')) {
- PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);
- PromptLineNum++;
- } else {
- for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
- if ((Temp == 0) && (Row <= BottomRow)) {
- //
- // 1.Clean the start LEFT_SKIPPED_COLUMNS
- //
- PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);
-
- if ((Statement->OpCode->OpCode == EFI_IFR_REF_OP) && (MenuOption->Col >= 2) && IsProcessingFirstRow) {
- //
- // Print Arrow for Goto button.
- //
- PrintCharAt (
- MenuOption->Col - 2,
- Row,
- GEOMETRICSHAPE_RIGHT_TRIANGLE
- );
- IsProcessingFirstRow = FALSE;
- }
-
- DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);
- PromptLineNum++;
- }
-
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&MenuOption->Description[Index]) != 0) {
- if (Temp == 0) {
- Row++;
- }
- }
-
- FreePool (OutputString);
- if (Temp != 0) {
- Temp--;
- }
- }
-
- Highlight = FALSE;
- }
-
- //
- // 3. If this is a text op with secondary text information
- //
- if ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)Statement->OpCode)->TextTwo != 0)) {
- StringPtr = GetToken (((EFI_IFR_TEXT *)Statement->OpCode)->TextTwo, gFormData->HiiHandle);
-
- Width = (UINT16)gOptionBlockWidth - 1;
- Row = MenuOption->Row;
- GlyphWidth = 1;
- OptionLineNum = 0;
-
- for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
- if ((Temp3 == 0) && (Row <= BottomRow)) {
- DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
- OptionLineNum++;
- }
-
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&StringPtr[Index]) != 0) {
- if (Temp3 == 0) {
- Row++;
- //
- // If the rows for text two is greater than or equal to the skip value, increase the skip value
- //
- if ((Row - MenuOption->Row) >= MenuOption->Skip) {
- MenuOption->Skip++;
- }
- }
- }
-
- FreePool (OutputString);
- if (Temp3 != 0) {
- Temp3--;
- }
- }
-
- FreePool (StringPtr);
- }
-
- //
- // 4.Line number for Option string and prompt string are not equal.
- // Clean the column whose line number is less.
- //
- if (HasOptionString (MenuOption) && (OptionLineNum != PromptLineNum)) {
- Col = OptionLineNum < PromptLineNum ? MenuOption->OptCol : BeginCol;
- Row = (OptionLineNum < PromptLineNum ? OptionLineNum : PromptLineNum) + MenuOption->Row;
- Width = (UINT16)(OptionLineNum < PromptLineNum ? gOptionBlockWidth : PromptWidth + AdjustValue + SkipWidth);
- MaxRow = (OptionLineNum < PromptLineNum ? PromptLineNum : OptionLineNum) + MenuOption->Row - 1;
-
- while (Row <= MaxRow) {
- DisplayMenuString (MenuOption, Col, Row++, L"", Width, FALSE);
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Display menu and wait for user to select one menu option, then return it.
- If AutoBoot is enabled, then if user doesn't select any option,
- after period of time, it will automatically return the first menu option.
-
- @param FormData The current form data info.
-
- @retval EFI_SUCESSS Process the user selection success.
- @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
-
-**/
-EFI_STATUS
-UiDisplayMenu (
- IN FORM_DISPLAY_ENGINE_FORM *FormData
- )
-{
- UINTN SkipValue;
- INTN Difference;
- UINTN DistanceValue;
- UINTN Row;
- UINTN Col;
- UINTN Temp;
- UINTN Temp2;
- UINTN TopRow;
- UINTN BottomRow;
- UINTN Index;
- CHAR16 *StringPtr;
- CHAR16 *StringRightPtr;
- CHAR16 *StringErrorPtr;
- CHAR16 *OptionString;
- CHAR16 *HelpString;
- CHAR16 *HelpHeaderString;
- CHAR16 *HelpBottomString;
- BOOLEAN NewLine;
- BOOLEAN Repaint;
- BOOLEAN UpArrow;
- BOOLEAN DownArrow;
- EFI_STATUS Status;
- EFI_INPUT_KEY Key;
- LIST_ENTRY *Link;
- LIST_ENTRY *NewPos;
- LIST_ENTRY *TopOfScreen;
- LIST_ENTRY *SavedListEntry;
- UI_MENU_OPTION *MenuOption;
- UI_MENU_OPTION *NextMenuOption;
- UI_MENU_OPTION *SavedMenuOption;
- UI_CONTROL_FLAG ControlFlag;
- UI_SCREEN_OPERATION ScreenOperation;
- FORM_DISPLAY_ENGINE_STATEMENT *Statement;
- BROWSER_HOT_KEY *HotKey;
- UINTN HelpPageIndex;
- UINTN HelpPageCount;
- UINTN RowCount;
- UINTN HelpLine;
- UINTN HelpHeaderLine;
- UINTN HelpBottomLine;
- BOOLEAN MultiHelpPage;
- UINT16 EachLineWidth;
- UINT16 HeaderLineWidth;
- UINT16 BottomLineWidth;
- EFI_STRING_ID HelpInfo;
- UI_EVENT_TYPE EventType;
- BOOLEAN SkipHighLight;
- EFI_HII_VALUE *StatementValue;
-
- EventType = UIEventNone;
- Status = EFI_SUCCESS;
- HelpString = NULL;
- HelpHeaderString = NULL;
- HelpBottomString = NULL;
- OptionString = NULL;
- ScreenOperation = UiNoOperation;
- NewLine = TRUE;
- HelpPageCount = 0;
- HelpLine = 0;
- RowCount = 0;
- HelpBottomLine = 0;
- HelpHeaderLine = 0;
- HelpPageIndex = 0;
- MultiHelpPage = FALSE;
- EachLineWidth = 0;
- HeaderLineWidth = 0;
- BottomLineWidth = 0;
- UpArrow = FALSE;
- DownArrow = FALSE;
- SkipValue = 0;
- SkipHighLight = FALSE;
-
- NextMenuOption = NULL;
- SavedMenuOption = NULL;
- HotKey = NULL;
- Repaint = TRUE;
- MenuOption = NULL;
- gModalSkipColumn = (CHAR16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;
-
- ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
-
- TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
- BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;
-
- Row = TopRow;
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;
- } else {
- Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;
- }
-
- FindTopMenu (FormData, &TopOfScreen, &NewPos, &SkipValue);
- if (!IsListEmpty (&gMenuOption)) {
- NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
- gUserInput->SelectedStatement = NextMenuOption->ThisTag;
- }
-
- gST->ConOut->EnableCursor (gST->ConOut, FALSE);
-
- ControlFlag = CfInitialization;
- while (TRUE) {
- switch (ControlFlag) {
- case CfInitialization:
- if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) ||
- (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid)))
- {
- //
- // Clear Statement range if different formset is painted.
- //
- ClearLines (
- gStatementDimensions.LeftColumn,
- gStatementDimensions.RightColumn,
- TopRow - SCROLL_ARROW_HEIGHT,
- BottomRow + SCROLL_ARROW_HEIGHT,
- GetFieldTextColor ()
- );
- }
-
- ControlFlag = CfRepaint;
- break;
-
- case CfRepaint:
- ControlFlag = CfRefreshHighLight;
-
- if (Repaint) {
- //
- // Display menu
- //
- DownArrow = FALSE;
- UpArrow = FALSE;
- Row = TopRow;
-
- gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
-
- //
- // 1. Check whether need to print the arrow up.
- //
- if (!ValueIsScroll (TRUE, TopOfScreen)) {
- UpArrow = TRUE;
- }
-
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
- } else {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
- }
-
- if (UpArrow) {
- gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
- PrintCharAt (
- gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
- TopRow - SCROLL_ARROW_HEIGHT,
- ARROW_UP
- );
- gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
- }
-
- //
- // 2.Paint the menu.
- //
- for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {
- MenuOption = MENU_OPTION_FROM_LINK (Link);
- MenuOption->Row = Row;
- MenuOption->Col = Col;
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth + gModalSkipColumn;
- } else {
- MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;
- }
-
- if (MenuOption->NestInStatement) {
- MenuOption->Col += SUBTITLE_INDENT;
- }
-
- //
- // Save the highlight menu, will be used in CfRefreshHighLight case.
- //
- if (Link == NewPos) {
- SavedMenuOption = MenuOption;
- SkipHighLight = TRUE;
- }
-
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- Status = DisplayOneMenu (
- MenuOption,
- MenuOption->Col - gStatementDimensions.LeftColumn,
- gStatementDimensions.LeftColumn + gModalSkipColumn,
- Link == TopOfScreen ? SkipValue : 0,
- BottomRow,
- (BOOLEAN)((Link == NewPos) && IsSelectable (MenuOption)),
- TRUE
- );
- } else {
- Status = DisplayOneMenu (
- MenuOption,
- MenuOption->Col - gStatementDimensions.LeftColumn,
- gStatementDimensions.LeftColumn,
- Link == TopOfScreen ? SkipValue : 0,
- BottomRow,
- (BOOLEAN)((Link == NewPos) && IsSelectable (MenuOption)),
- TRUE
- );
- }
-
- if (EFI_ERROR (Status)) {
- if (gMisMatch) {
- return EFI_SUCCESS;
- } else {
- return Status;
- }
- }
-
- //
- // 3. Update the row info which will be used by next menu.
- //
- if (Link == TopOfScreen) {
- Row += MenuOption->Skip - SkipValue;
- } else {
- Row += MenuOption->Skip;
- }
-
- if (Row > BottomRow) {
- if (!ValueIsScroll (FALSE, Link)) {
- DownArrow = TRUE;
- }
-
- Row = BottomRow + 1;
- break;
- }
- }
-
- //
- // 3. Menus in this form may not cover all form, clean the remain field.
- //
- while (Row <= BottomRow) {
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
- } else {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);
- }
- }
-
- //
- // 4. Print the down arrow row.
- //
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * +gModalSkipColumn);
- } else {
- PrintStringAtWithWidth (gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
- }
-
- if (DownArrow) {
- gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
- PrintCharAt (
- gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
- BottomRow + SCROLL_ARROW_HEIGHT,
- ARROW_DOWN
- );
- gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
- }
-
- MenuOption = NULL;
- }
-
- break;
-
- case CfRefreshHighLight:
-
- //
- // MenuOption: Last menu option that need to remove hilight
- // MenuOption is set to NULL in Repaint
- // NewPos: Current menu option that need to hilight
- //
- ControlFlag = CfUpdateHelpString;
-
- ASSERT (NewPos != NULL);
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
-
- if (SkipHighLight) {
- SkipHighLight = FALSE;
- MenuOption = SavedMenuOption;
- RefreshKeyHelp (gFormData, SavedMenuOption->ThisTag, FALSE);
- break;
- }
-
- if (IsListEmpty (&gMenuOption)) {
- //
- // No menu option, just update the hotkey filed.
- //
- RefreshKeyHelp (gFormData, NULL, FALSE);
- break;
- }
-
- if ((MenuOption != NULL) && (TopOfScreen == &MenuOption->Link)) {
- Temp = SkipValue;
- } else {
- Temp = 0;
- }
-
- if (NewPos == TopOfScreen) {
- Temp2 = SkipValue;
- } else {
- Temp2 = 0;
- }
-
- if ((MenuOption == NULL) || (NewPos != &MenuOption->Link)) {
- if (MenuOption != NULL) {
- //
- // Remove the old highlight menu.
- //
- Status = DisplayOneMenu (
- MenuOption,
- MenuOption->Col - gStatementDimensions.LeftColumn,
- gStatementDimensions.LeftColumn,
- Temp,
- BottomRow,
- FALSE,
- FALSE
- );
- }
-
- //
- // This is the current selected statement
- //
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- RefreshKeyHelp (gFormData, MenuOption->ThisTag, FALSE);
-
- if (!IsSelectable (MenuOption)) {
- break;
- }
-
- Status = DisplayOneMenu (
- MenuOption,
- MenuOption->Col - gStatementDimensions.LeftColumn,
- gStatementDimensions.LeftColumn,
- Temp2,
- BottomRow,
- TRUE,
- FALSE
- );
- }
-
- break;
-
- case CfUpdateHelpString:
- ControlFlag = CfPrepareToReadKey;
- if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
- break;
- }
-
- //
- // NewLine means only update highlight menu (remove old highlight and highlith
- // the new one), not need to full repain the form.
- //
- if (Repaint || NewLine) {
- if (IsListEmpty (&gMenuOption)) {
- //
- // Don't print anything if no mwnu option.
- //
- StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
- } else {
- //
- // Don't print anything if it is a NULL help token
- //
- ASSERT (MenuOption != NULL);
- HelpInfo = ((EFI_IFR_STATEMENT_HEADER *)((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;
- Statement = MenuOption->ThisTag;
- StatementValue = &Statement->CurrentValue;
- if ((HelpInfo == 0) || !IsSelectable (MenuOption)) {
- if (((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) && (StatementValue->Value.date.Month == 0xff)) || ((Statement->OpCode->OpCode == EFI_IFR_TIME_OP) && (StatementValue->Value.time.Hour == 0xff))) {
- StringPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
- } else {
- StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
- }
- } else {
- if (((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) && (StatementValue->Value.date.Month == 0xff)) || ((Statement->OpCode->OpCode == EFI_IFR_TIME_OP) && (StatementValue->Value.time.Hour == 0xff))) {
- StringRightPtr = GetToken (HelpInfo, gFormData->HiiHandle);
- StringErrorPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
- StringPtr = AllocateZeroPool ((StrLen (StringRightPtr) + StrLen (StringErrorPtr)+ 1) * sizeof (CHAR16));
- StrCpyS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringRightPtr);
- StrCatS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringErrorPtr);
- FreePool (StringRightPtr);
- FreePool (StringErrorPtr);
- } else {
- StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);
- }
- }
- }
-
- RowCount = BottomRow - TopRow + 1;
- HelpPageIndex = 0;
- //
- // 1.Calculate how many line the help string need to print.
- //
- if (HelpString != NULL) {
- FreePool (HelpString);
- HelpString = NULL;
- }
-
- HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);
- FreePool (StringPtr);
-
- if (HelpLine > RowCount) {
- MultiHelpPage = TRUE;
- StringPtr = GetToken (STRING_TOKEN (ADJUST_HELP_PAGE_UP), gHiiHandle);
- if (HelpHeaderString != NULL) {
- FreePool (HelpHeaderString);
- HelpHeaderString = NULL;
- }
-
- HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0);
- FreePool (StringPtr);
- StringPtr = GetToken (STRING_TOKEN (ADJUST_HELP_PAGE_DOWN), gHiiHandle);
- if (HelpBottomString != NULL) {
- FreePool (HelpBottomString);
- HelpBottomString = NULL;
- }
-
- HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);
- FreePool (StringPtr);
- //
- // Calculate the help page count.
- //
- if (HelpLine > 2 * RowCount - 2) {
- HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;
- if ((HelpLine - RowCount + 1) % (RowCount - 2) != 0) {
- HelpPageCount += 1;
- }
- } else {
- HelpPageCount = 2;
- }
- } else {
- MultiHelpPage = FALSE;
- }
- }
-
- //
- // Check whether need to show the 'More(U/u)' at the begin.
- // Base on current direct info, here shows aligned to the right side of the column.
- // If the direction is multi line and aligned to right side may have problem, so
- // add ASSERT code here.
- //
- if (HelpPageIndex > 0) {
- gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
- for (Index = 0; Index < HelpHeaderLine; Index++) {
- ASSERT (HelpHeaderLine == 1);
- ASSERT (GetStringWidth (HelpHeaderString) / 2 < ((UINT32)gHelpBlockWidth - 1));
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow,
- gEmptyString,
- gHelpBlockWidth
- );
- PrintStringAt (
- gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,
- Index + TopRow,
- &HelpHeaderString[Index * HeaderLineWidth]
- );
- }
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());
- //
- // Print the help string info.
- //
- if (!MultiHelpPage) {
- for (Index = 0; Index < HelpLine; Index++) {
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow,
- &HelpString[Index * EachLineWidth],
- gHelpBlockWidth
- );
- }
-
- for ( ; Index < RowCount; Index++) {
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow,
- gEmptyString,
- gHelpBlockWidth
- );
- }
-
- gST->ConOut->SetCursorPosition (gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
- } else {
- if (HelpPageIndex == 0) {
- for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow,
- &HelpString[Index * EachLineWidth],
- gHelpBlockWidth
- );
- }
- } else {
- for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) &&
- (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++)
- {
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow + HelpHeaderLine,
- &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth],
- gHelpBlockWidth
- );
- }
-
- if (HelpPageIndex == HelpPageCount - 1) {
- for ( ; Index < RowCount - HelpHeaderLine; Index++) {
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- Index + TopRow + HelpHeaderLine,
- gEmptyString,
- gHelpBlockWidth
- );
- }
-
- gST->ConOut->SetCursorPosition (gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
- }
- }
- }
-
- //
- // Check whether need to print the 'More(D/d)' at the bottom.
- // Base on current direct info, here shows aligned to the right side of the column.
- // If the direction is multi line and aligned to right side may have problem, so
- // add ASSERT code here.
- //
- if ((HelpPageIndex < HelpPageCount - 1) && MultiHelpPage) {
- gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
- for (Index = 0; Index < HelpBottomLine; Index++) {
- ASSERT (HelpBottomLine == 1);
- ASSERT (GetStringWidth (HelpBottomString) / 2 < ((UINT32)gHelpBlockWidth - 1));
- PrintStringAtWithWidth (
- gStatementDimensions.RightColumn - gHelpBlockWidth,
- BottomRow + Index - HelpBottomLine + 1,
- gEmptyString,
- gHelpBlockWidth
- );
- PrintStringAt (
- gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,
- BottomRow + Index - HelpBottomLine + 1,
- &HelpBottomString[Index * BottomLineWidth]
- );
- }
- }
-
- //
- // Reset this flag every time we finish using it.
- //
- Repaint = FALSE;
- NewLine = FALSE;
- break;
-
- case CfPrepareToReadKey:
- ControlFlag = CfReadKey;
- ScreenOperation = UiNoOperation;
- break;
-
- case CfReadKey:
- ControlFlag = CfScreenOperation;
-
- //
- // Wait for user's selection
- //
- while (TRUE) {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (!EFI_ERROR (Status)) {
- EventType = UIEventKey;
- break;
- }
-
- //
- // If we encounter error, continue to read another key in.
- //
- if (Status != EFI_NOT_READY) {
- continue;
- }
-
- EventType = UiWaitForEvent (gST->ConIn->WaitForKey);
- if (EventType == UIEventKey) {
- gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- }
-
- break;
- }
-
- if (EventType == UIEventDriver) {
- gMisMatch = TRUE;
- gUserInput->Action = BROWSER_ACTION_NONE;
- ControlFlag = CfExit;
- break;
- }
-
- if (EventType == UIEventTimeOut) {
- gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
- ControlFlag = CfExit;
- break;
- }
-
- switch (Key.UnicodeChar) {
- case CHAR_CARRIAGE_RETURN:
- if ((MenuOption == NULL) || MenuOption->GrayOut || MenuOption->ReadOnly) {
- ControlFlag = CfReadKey;
- break;
- }
-
- ScreenOperation = UiSelect;
- gDirection = 0;
- break;
-
- //
- // We will push the adjustment of these numeric values directly to the input handler
- // NOTE: we won't handle manual input numeric
- //
- case '+':
- case '-':
- //
- // If the screen has no menu items, and the user didn't select UiReset
- // ignore the selection and go back to reading keys.
- //
- ASSERT (MenuOption != NULL);
- if (IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {
- ControlFlag = CfReadKey;
- break;
- }
-
- Statement = MenuOption->ThisTag;
- if ( (Statement->OpCode->OpCode == EFI_IFR_DATE_OP)
- || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)
- || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum (Statement->OpCode) != 0))
- )
- {
- if (Key.UnicodeChar == '+') {
- gDirection = SCAN_RIGHT;
- } else {
- gDirection = SCAN_LEFT;
- }
-
- Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
- if (OptionString != NULL) {
- FreePool (OptionString);
- }
-
- if (EFI_ERROR (Status)) {
- //
- // Repaint to clear possible error prompt pop-up
- //
- Repaint = TRUE;
- NewLine = TRUE;
- } else {
- ControlFlag = CfExit;
- }
- }
-
- break;
-
- case '^':
- ScreenOperation = UiUp;
- break;
-
- case 'V':
- case 'v':
- ScreenOperation = UiDown;
- break;
-
- case ' ':
- if (IsListEmpty (&gMenuOption)) {
- ControlFlag = CfReadKey;
- break;
- }
-
- ASSERT (MenuOption != NULL);
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP) && !MenuOption->GrayOut && !MenuOption->ReadOnly) {
- ScreenOperation = UiSelect;
- }
-
- break;
-
- case 'D':
- case 'd':
- if (!MultiHelpPage) {
- ControlFlag = CfReadKey;
- break;
- }
-
- ControlFlag = CfUpdateHelpString;
- HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;
- break;
-
- case 'U':
- case 'u':
- if (!MultiHelpPage) {
- ControlFlag = CfReadKey;
- break;
- }
-
- ControlFlag = CfUpdateHelpString;
- HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;
- break;
-
- case CHAR_NULL:
- for (Index = 0; Index < mScanCodeNumber; Index++) {
- if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
- ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
- break;
- }
- }
-
- if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && ((Key.ScanCode == SCAN_ESC) || (Index == mScanCodeNumber))) {
- //
- // ModalForm has no ESC key and Hot Key.
- //
- ControlFlag = CfReadKey;
- } else if (Index == mScanCodeNumber) {
- //
- // Check whether Key matches the registered hot key.
- //
- HotKey = NULL;
- HotKey = GetHotKeyFromRegisterList (&Key);
- if (HotKey != NULL) {
- ScreenOperation = UiHotKey;
- }
- }
-
- break;
- }
-
- break;
-
- case CfScreenOperation:
- if ((ScreenOperation != UiReset) && (ScreenOperation != UiHotKey)) {
- //
- // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
- // ignore the selection and go back to reading keys.
- //
- if (IsListEmpty (&gMenuOption)) {
- ControlFlag = CfReadKey;
- break;
- }
- }
-
- for (Index = 0;
- Index < ARRAY_SIZE (gScreenOperationToControlFlag);
- Index++
- )
- {
- if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
- ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
- break;
- }
- }
-
- break;
-
- case CfUiSelect:
- ControlFlag = CfRepaint;
-
- ASSERT (MenuOption != NULL);
- Statement = MenuOption->ThisTag;
- if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
- break;
- }
-
- switch (Statement->OpCode->OpCode) {
- case EFI_IFR_REF_OP:
- case EFI_IFR_ACTION_OP:
- case EFI_IFR_RESET_BUTTON_OP:
- ControlFlag = CfExit;
- break;
-
- default:
- //
- // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
- //
- RefreshKeyHelp (gFormData, Statement, TRUE);
- Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
-
- if (OptionString != NULL) {
- FreePool (OptionString);
- }
-
- if (EFI_ERROR (Status)) {
- Repaint = TRUE;
- NewLine = TRUE;
- RefreshKeyHelp (gFormData, Statement, FALSE);
- break;
- } else {
- ControlFlag = CfExit;
- break;
- }
- }
-
- break;
-
- case CfUiReset:
- //
- // We come here when someone press ESC
- // If the policy is not exit front page when user press ESC, process here.
- //
- if (!FormExitPolicy ()) {
- Repaint = TRUE;
- NewLine = TRUE;
- ControlFlag = CfRepaint;
- break;
- }
-
- gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
- ControlFlag = CfExit;
- break;
-
- case CfUiHotKey:
- ControlFlag = CfRepaint;
-
- ASSERT (HotKey != NULL);
-
- if (FxConfirmPopup (HotKey->Action)) {
- gUserInput->Action = HotKey->Action;
- if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
- gUserInput->DefaultId = HotKey->DefaultId;
- }
-
- ControlFlag = CfExit;
- } else {
- Repaint = TRUE;
- NewLine = TRUE;
- ControlFlag = CfRepaint;
- }
-
- break;
-
- case CfUiLeft:
- ControlFlag = CfRepaint;
- ASSERT (MenuOption != NULL);
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- if (MenuOption->Sequence != 0) {
- //
- // In the middle or tail of the Date/Time op-code set, go left.
- //
- ASSERT (NewPos != NULL);
- NewPos = NewPos->BackLink;
- }
- }
-
- break;
-
- case CfUiRight:
- ControlFlag = CfRepaint;
- ASSERT (MenuOption != NULL);
- if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- if (MenuOption->Sequence != 2) {
- //
- // In the middle or tail of the Date/Time op-code set, go left.
- //
- ASSERT (NewPos != NULL);
- NewPos = NewPos->ForwardLink;
- }
- }
-
- break;
-
- case CfUiUp:
- ControlFlag = CfRepaint;
- NewLine = TRUE;
-
- SavedListEntry = NewPos;
- ASSERT (NewPos != NULL);
-
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- ASSERT (MenuOption != NULL);
-
- //
- // Adjust Date/Time position before we advance forward.
- //
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- NewPos = NewPos->BackLink;
- //
- // Find next selectable menu or the first menu beyond current form.
- //
- Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow, FALSE);
- if (Difference < 0) {
- //
- // We hit the begining MenuOption that can be focused
- // so we simply scroll to the top.
- //
- Repaint = TRUE;
- if ((TopOfScreen != gMenuOption.ForwardLink) || (SkipValue != 0)) {
- TopOfScreen = gMenuOption.ForwardLink;
- NewPos = SavedListEntry;
- SkipValue = 0;
- } else {
- //
- // Scroll up to the last page when we have arrived at top page.
- //
- TopOfScreen = FindTopOfScreenMenu (gMenuOption.BackLink, BottomRow - TopRow, &SkipValue);
- NewPos = gMenuOption.BackLink;
- MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow, TRUE);
- }
- } else {
- NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- if (MenuOption->Row < TopRow + Difference + NextMenuOption->Skip) {
- //
- // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
- //
- TopOfScreen = NewPos;
- Repaint = TRUE;
- SkipValue = 0;
- }
-
- //
- // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
- //
- // BottomRow - TopRow + 1 means the total rows current forms supported.
- // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
- // and new top menu. New top menu will all shows in next form, but last highlight menu
- // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
- // last highlight menu.
- //
- if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) &&
- (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1))
- {
- NewPos = SavedListEntry;
- }
- }
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
- break;
-
- case CfUiPageUp:
- //
- // SkipValue means lines is skipped when show the top menu option.
- //
- ControlFlag = CfRepaint;
- NewLine = TRUE;
- Repaint = TRUE;
-
- Link = TopOfScreen;
- //
- // First minus the menu of the top screen, it's value is SkipValue.
- //
- if (SkipValue >= BottomRow - TopRow + 1) {
- //
- // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
- // form of options to be show, so just update the SkipValue to show the next
- // parts of options.
- //
- SkipValue -= BottomRow - TopRow + 1;
- NewPos = TopOfScreen;
- break;
- } else {
- Index = (BottomRow + 1) - SkipValue - TopRow;
- }
-
- TopOfScreen = FindTopOfScreenMenu (TopOfScreen, Index, &SkipValue);
- NewPos = TopOfScreen;
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, FALSE);
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- // Don't do this when we are already in the first page.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
- break;
-
- case CfUiPageDown:
- //
- // SkipValue means lines is skipped when show the top menu option.
- //
- ControlFlag = CfRepaint;
- NewLine = TRUE;
- Repaint = TRUE;
-
- Link = TopOfScreen;
- NextMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index = TopRow + NextMenuOption->Skip - SkipValue;
- //
- // Count to the menu option which will show at the top of the next form.
- //
- while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {
- Link = Link->ForwardLink;
- NextMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index = Index + NextMenuOption->Skip;
- }
-
- if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {
- //
- // Highlight on the last menu which can be highlight.
- //
- Repaint = FALSE;
- MoveToNextStatement (TRUE, &Link, Index - TopRow, TRUE);
- } else {
- //
- // Calculate the skip line for top of screen menu.
- //
- if (Link == TopOfScreen) {
- //
- // The top of screen menu option occupies the entire form.
- //
- SkipValue += BottomRow - TopRow + 1;
- } else {
- SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));
- }
-
- TopOfScreen = Link;
- MenuOption = NULL;
- //
- // Move to the Next selectable menu.
- //
- MoveToNextStatement (FALSE, &Link, BottomRow - TopRow, TRUE);
- }
-
- //
- // Save the menu as the next highlight menu.
- //
- NewPos = Link;
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- // Don't do this when we are already in the last page.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
- break;
-
- case CfUiDown:
- //
- // SkipValue means lines is skipped when show the top menu option.
- // NewPos points to the menu which is highlighted now.
- //
- ControlFlag = CfRepaint;
- NewLine = TRUE;
-
- if (NewPos == TopOfScreen) {
- Temp2 = SkipValue;
- } else {
- Temp2 = 0;
- }
-
- SavedListEntry = NewPos;
- //
- // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
- // to be one that progresses to the next set of op-codes, we need to advance to the last
- // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
- // checking can be done. The only other logic we need to introduce is that if a Date/Time
- // op-code is the last entry in the menu, we need to rewind back to the first op-code of
- // the Date/Time op-code.
- //
- AdjustDateAndTimePosition (FALSE, &NewPos);
-
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- NewPos = NewPos->ForwardLink;
- //
- // Find the next selectable menu.
- //
- if (MenuOption->Row + MenuOption->Skip - Temp2 > BottomRow + 1) {
- if ((gMenuOption.ForwardLink == NewPos) || (&gMenuOption == NewPos)) {
- Difference = -1;
- } else {
- Difference = 0;
- }
- } else {
- Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow + 1 - (MenuOption->Row + MenuOption->Skip - Temp2), FALSE);
- }
-
- if (Difference < 0) {
- //
- // Scroll to the first page.
- //
- if ((TopOfScreen != gMenuOption.ForwardLink) || (SkipValue != 0)) {
- TopOfScreen = gMenuOption.ForwardLink;
- Repaint = TRUE;
- MenuOption = NULL;
- } else {
- MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
- }
-
- NewPos = gMenuOption.ForwardLink;
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);
-
- SkipValue = 0;
- //
- // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
- break;
- }
-
- //
- // Get next selected menu info.
- //
- AdjustDateAndTimePosition (FALSE, &NewPos);
- NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
- if (NextMenuOption->Row == 0) {
- UpdateOptionSkipLines (NextMenuOption);
- }
-
- //
- // Calculate new highlight menu end row.
- //
- Temp = (MenuOption->Row + MenuOption->Skip - Temp2) + Difference + NextMenuOption->Skip - 1;
- if (Temp > BottomRow) {
- //
- // Get the top screen menu info.
- //
- AdjustDateAndTimePosition (FALSE, &TopOfScreen);
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
- //
- // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
- // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
- //
- if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {
- //
- // Skip the top op-code
- //
- TopOfScreen = TopOfScreen->ForwardLink;
- DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);
-
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
- //
- // If we have a remainder, skip that many more op-codes until we drain the remainder
- // Special case is the selected highlight menu has more than one form of menus.
- //
- while (DistanceValue >= SavedMenuOption->Skip && TopOfScreen != NewPos) {
- //
- // Since the Difference is greater than or equal to this op-code's skip value, skip it
- //
- DistanceValue = DistanceValue - (INTN)SavedMenuOption->Skip;
- TopOfScreen = TopOfScreen->ForwardLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
- }
-
- //
- // Since we will act on this op-code in the next routine, and increment the
- // SkipValue, set the skips to one less than what is required.
- //
- if (TopOfScreen != NewPos) {
- SkipValue = DistanceValue;
- } else {
- SkipValue = 0;
- }
- } else {
- //
- // Since we will act on this op-code in the next routine, and increment the
- // SkipValue, set the skips to one less than what is required.
- //
- SkipValue += Temp - BottomRow;
- }
-
- Repaint = TRUE;
- } else if (!IsSelectable (NextMenuOption)) {
- //
- // Continue to go down until scroll to next page or the selectable option is found.
- //
- ScreenOperation = UiDown;
- ControlFlag = CfScreenOperation;
- break;
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
-
- //
- // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
- //
- // BottomRow - TopRow + 1 means the total rows current forms supported.
- // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
- // and new top menu. New top menu will all shows in next form, but last highlight menu
- // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
- // last highlight menu.
- //
- if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) &&
- (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1))
- {
- NewPos = SavedListEntry;
- }
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
-
- //
- // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
- break;
-
- case CfUiNoOperation:
- ControlFlag = CfRepaint;
- break;
-
- case CfExit:
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- if (HelpString != NULL) {
- FreePool (HelpString);
- }
-
- if (HelpHeaderString != NULL) {
- FreePool (HelpHeaderString);
- }
-
- if (HelpBottomString != NULL) {
- FreePool (HelpBottomString);
- }
-
- return EFI_SUCCESS;
-
- default:
- break;
- }
- }
-}
-
-/**
- Free the UI Menu Option structure data.
-
- @param MenuOptionList Point to the menu option list which need to be free.
-
-**/
-VOID
-FreeMenuOptionData (
- LIST_ENTRY *MenuOptionList
- )
-{
- LIST_ENTRY *Link;
- UI_MENU_OPTION *Option;
-
- //
- // Free menu option list
- //
- while (!IsListEmpty (MenuOptionList)) {
- Link = GetFirstNode (MenuOptionList);
- Option = MENU_OPTION_FROM_LINK (Link);
- if (Option->Description != NULL) {
- FreePool (Option->Description);
- }
-
- RemoveEntryList (&Option->Link);
- FreePool (Option);
- }
-}
-
-/**
-
- Base on the browser status info to show an pop up message.
-
-**/
-VOID
-BrowserStatusProcess (
- VOID
- )
-{
- CHAR16 *ErrorInfo;
- EFI_INPUT_KEY Key;
- EFI_EVENT WaitList[2];
- EFI_EVENT RefreshIntervalEvent;
- EFI_EVENT TimeOutEvent;
- UINT8 TimeOut;
- EFI_STATUS Status;
- UINTN Index;
- WARNING_IF_CONTEXT EventContext;
- EFI_IFR_OP_HEADER *OpCodeBuf;
- EFI_STRING_ID StringToken;
- CHAR16 DiscardChange;
- CHAR16 JumpToFormSet;
- CHAR16 *PrintString;
-
- if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
- return;
- }
-
- StringToken = 0;
- TimeOutEvent = NULL;
- RefreshIntervalEvent = NULL;
- OpCodeBuf = NULL;
- if (gFormData->HighLightedStatement != NULL) {
- OpCodeBuf = gFormData->HighLightedStatement->OpCode;
- }
-
- if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {
- ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);
-
- TimeOut = ((EFI_IFR_WARNING_IF *)OpCodeBuf)->TimeOut;
- StringToken = ((EFI_IFR_WARNING_IF *)OpCodeBuf)->Warning;
- } else {
- TimeOut = 0;
- if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&
- ((OpCodeBuf != NULL) && (OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)))
- {
- StringToken = ((EFI_IFR_NO_SUBMIT_IF *)OpCodeBuf)->Error;
- } else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&
- ((OpCodeBuf != NULL) && (OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)))
- {
- StringToken = ((EFI_IFR_INCONSISTENT_IF *)OpCodeBuf)->Error;
- }
- }
-
- if (StringToken != 0) {
- ErrorInfo = GetToken (StringToken, gFormData->HiiHandle);
- } else if (gFormData->ErrorString != NULL) {
- //
- // Only used to compatible with old setup browser.
- // Not use this field in new browser core.
- //
- ErrorInfo = gFormData->ErrorString;
- } else {
- switch (gFormData->BrowserStatus) {
- case BROWSER_SUBMIT_FAIL:
- ErrorInfo = gSaveFailed;
- break;
-
- case BROWSER_FORM_NOT_FOUND:
- ErrorInfo = gFormNotFound;
- break;
-
- case BROWSER_FORM_SUPPRESS:
- ErrorInfo = gFormSuppress;
- break;
-
- case BROWSER_PROTOCOL_NOT_FOUND:
- ErrorInfo = gProtocolNotFound;
- break;
-
- case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
- ErrorInfo = gNoSubmitIfFailed;
- break;
-
- case BROWSER_RECONNECT_FAIL:
- ErrorInfo = gReconnectFail;
- break;
-
- case BROWSER_RECONNECT_SAVE_CHANGES:
- ErrorInfo = gReconnectConfirmChanges;
- break;
-
- case BROWSER_RECONNECT_REQUIRED:
- ErrorInfo = gReconnectRequired;
- break;
-
- default:
- ErrorInfo = gBrowserError;
- break;
- }
- }
-
- switch (gFormData->BrowserStatus) {
- case BROWSER_SUBMIT_FAIL:
- case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
- case BROWSER_RECONNECT_SAVE_CHANGES:
- ASSERT (gUserInput != NULL);
- if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) {
- PrintString = gSaveProcess;
- JumpToFormSet = gJumpToFormSet[0];
- DiscardChange = gDiscardChange[0];
- } else if (gFormData->BrowserStatus == (BROWSER_RECONNECT_SAVE_CHANGES)) {
- PrintString = gChangesOpt;
- JumpToFormSet = gConfirmOptYes[0];
- DiscardChange = gConfirmOptNo[0];
- } else {
- PrintString = gSaveNoSubmitProcess;
- JumpToFormSet = gCheckError[0];
- DiscardChange = gDiscardChange[0];
- }
-
- do {
- CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL);
- } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET)));
-
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) {
- gUserInput->Action = BROWSER_ACTION_DISCARD;
- } else {
- gUserInput->Action = BROWSER_ACTION_GOTO;
- }
-
- break;
-
- default:
- if (TimeOut == 0) {
- do {
- CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
- } else {
- Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent);
- ASSERT_EFI_ERROR (Status);
-
- EventContext.SyncEvent = TimeOutEvent;
- EventContext.TimeOut = &TimeOut;
- EventContext.ErrorInfo = ErrorInfo;
-
- Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Show the dialog first to avoid long time not reaction.
- //
- gBS->SignalEvent (RefreshIntervalEvent);
-
- Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND);
- ASSERT_EFI_ERROR (Status);
-
- while (TRUE) {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (!EFI_ERROR (Status) && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
- break;
- }
-
- if (Status != EFI_NOT_READY) {
- continue;
- }
-
- WaitList[0] = TimeOutEvent;
- WaitList[1] = gST->ConIn->WaitForKey;
-
- Status = gBS->WaitForEvent (2, WaitList, &Index);
- ASSERT_EFI_ERROR (Status);
-
- if (Index == 0) {
- //
- // Timeout occur, close the hoot time out event.
- //
- break;
- }
- }
-
- gBS->CloseEvent (TimeOutEvent);
- gBS->CloseEvent (RefreshIntervalEvent);
- }
-
- break;
- }
-
- if (StringToken != 0) {
- FreePool (ErrorInfo);
- }
-}
-
-/**
- Display one form, and return user input.
-
- @param FormData Form Data to be shown.
- @param UserInputData User input data.
-
- @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
- 2.Error info has show and return.
- @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
- @retval EFI_NOT_FOUND New form data has some error.
-**/
-EFI_STATUS
-EFIAPI
-FormDisplay (
- IN FORM_DISPLAY_ENGINE_FORM *FormData,
- OUT USER_INPUT *UserInputData
- )
-{
- EFI_STATUS Status;
-
- ASSERT (FormData != NULL);
- if (FormData == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- gUserInput = UserInputData;
- gFormData = FormData;
-
- //
- // Process the status info first.
- //
- BrowserStatusProcess ();
- if (gFormData->BrowserStatus != BROWSER_SUCCESS) {
- //
- // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
- //
- return EFI_SUCCESS;
- }
-
- Status = DisplayPageFrame (FormData, &gStatementDimensions);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Global Widths should be initialized before any MenuOption creation
- // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
- //
- //
- // Left right
- // |<-.->|<-.........->|<- .........->|<-...........->|
- // Skip Prompt Option Help
- //
- gOptionBlockWidth = (CHAR16)((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3) + 1;
- gHelpBlockWidth = (CHAR16)(gOptionBlockWidth - 1 - LEFT_SKIPPED_COLUMNS);
- gPromptBlockWidth = (CHAR16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gOptionBlockWidth - 1) - 1);
-
- ConvertStatementToMenu ();
-
- //
- // Check whether layout is changed.
- //
- if ( mIsFirstForm
- || (gOldFormEntry.HiiHandle != FormData->HiiHandle)
- || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))
- || (gOldFormEntry.FormId != FormData->FormId))
- {
- mStatementLayoutIsChanged = TRUE;
- } else {
- mStatementLayoutIsChanged = FALSE;
- }
-
- Status = UiDisplayMenu (FormData);
-
- //
- // Backup last form info.
- //
- mIsFirstForm = FALSE;
- gOldFormEntry.HiiHandle = FormData->HiiHandle;
- CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid);
- gOldFormEntry.FormId = FormData->FormId;
-
- //
- // Free the Ui menu option list.
- //
- FreeMenuOptionData (&gMenuOption);
-
- return Status;
-}
-
-/**
- Clear Screen to the initial state.
-**/
-VOID
-EFIAPI
-DriverClearDisplayPage (
- VOID
- )
-{
- ClearDisplayPage ();
- mIsFirstForm = TRUE;
-}
-
-/**
- Set Buffer to Value for Size bytes.
-
- @param Buffer Memory to set.
- @param Size Number of bytes to set
- @param Value Value of the set operation.
-
-**/
-VOID
-SetUnicodeMem (
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR16 Value
- )
-{
- CHAR16 *Ptr;
-
- Ptr = Buffer;
- while ((Size--) != 0) {
- *(Ptr++) = Value;
- }
-}
-
-/**
- Initialize Setup Browser driver.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
- @return Other value if failed to initialize the Setup Browser module.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeDisplayEngine (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- EFI_INPUT_KEY HotKey;
- EFI_STRING NewString;
- EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
-
- //
- // Publish our HII data
- //
- gHiiHandle = HiiAddPackages (
- &gDisplayEngineGuid,
- ImageHandle,
- DisplayEngineStrings,
- NULL
- );
- ASSERT (gHiiHandle != NULL);
-
- //
- // Install Form Display protocol
- //
- Status = gBS->InstallProtocolInterface (
- &mPrivateData.Handle,
- &gEdkiiFormDisplayEngineProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPrivateData.FromDisplayProt
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Install HII Popup Protocol.
- //
- Status = gBS->InstallProtocolInterface (
- &mPrivateData.Handle,
- &gEfiHiiPopupProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPrivateData.HiiPopup
- );
- ASSERT_EFI_ERROR (Status);
-
- InitializeDisplayStrings ();
-
- ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo));
- ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry));
-
- //
- // Use BrowserEx2 protocol to register HotKey.
- //
- Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);
- if (!EFI_ERROR (Status)) {
- //
- // Register the default HotKey F9 and F10 again.
- //
- HotKey.UnicodeChar = CHAR_NULL;
- HotKey.ScanCode = SCAN_F10;
- NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL);
- ASSERT (NewString != NULL);
- FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);
- FreePool (NewString);
-
- HotKey.ScanCode = SCAN_F9;
- NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL);
- ASSERT (NewString != NULL);
- FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);
- FreePool (NewString);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This is the default unload handle for display core drivers.
-
- @param[in] ImageHandle The drivers' driver image.
-
- @retval EFI_SUCCESS The image is unloaded.
- @retval Others Failed to unload the image.
-
-**/
-EFI_STATUS
-EFIAPI
-UnloadDisplayEngine (
- IN EFI_HANDLE ImageHandle
- )
-{
- HiiRemovePackages (gHiiHandle);
-
- FreeDisplayStrings ();
-
- if (gHighligthMenuInfo.HLTOpCode != NULL) {
- FreePool (gHighligthMenuInfo.HLTOpCode);
- }
-
- if (gHighligthMenuInfo.TOSOpCode != NULL) {
- FreePool (gHighligthMenuInfo.TOSOpCode);
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+Entry and initialization module for the browser.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FormDisplay.h"
+
+//
+// Search table for UiDisplayMenu()
+//
+SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
+ {
+ SCAN_UP,
+ UiUp,
+ },
+ {
+ SCAN_DOWN,
+ UiDown,
+ },
+ {
+ SCAN_PAGE_UP,
+ UiPageUp,
+ },
+ {
+ SCAN_PAGE_DOWN,
+ UiPageDown,
+ },
+ {
+ SCAN_ESC,
+ UiReset,
+ },
+ {
+ SCAN_LEFT,
+ UiLeft,
+ },
+ {
+ SCAN_RIGHT,
+ UiRight,
+ }
+};
+
+UINTN mScanCodeNumber = ARRAY_SIZE (gScanCodeToOperation);
+
+SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
+ {
+ UiNoOperation,
+ CfUiNoOperation,
+ },
+ {
+ UiSelect,
+ CfUiSelect,
+ },
+ {
+ UiUp,
+ CfUiUp,
+ },
+ {
+ UiDown,
+ CfUiDown,
+ },
+ {
+ UiLeft,
+ CfUiLeft,
+ },
+ {
+ UiRight,
+ CfUiRight,
+ },
+ {
+ UiReset,
+ CfUiReset,
+ },
+ {
+ UiPageUp,
+ CfUiPageUp,
+ },
+ {
+ UiPageDown,
+ CfUiPageDown
+ },
+ {
+ UiHotKey,
+ CfUiHotKey
+ }
+};
+
+EFI_GUID gDisplayEngineGuid = {
+ 0xE38C1029, 0xE38F, 0x45b9, { 0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62 }
+};
+
+BOOLEAN gMisMatch;
+EFI_SCREEN_DESCRIPTOR gStatementDimensions;
+BOOLEAN mStatementLayoutIsChanged = TRUE;
+USER_INPUT *gUserInput;
+FORM_DISPLAY_ENGINE_FORM *gFormData;
+EFI_HII_HANDLE gHiiHandle;
+UINT16 gDirection;
+LIST_ENTRY gMenuOption;
+DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = { 0 };
+BOOLEAN mIsFirstForm = TRUE;
+FORM_ENTRY_INFO gOldFormEntry = { 0 };
+
+//
+// Browser Global Strings
+//
+CHAR16 *gReconnectConfirmChanges;
+CHAR16 *gReconnectFail;
+CHAR16 *gReconnectRequired;
+CHAR16 *gChangesOpt;
+CHAR16 *gFormNotFound;
+CHAR16 *gNoSubmitIf;
+CHAR16 *gBrowserError;
+CHAR16 *gSaveFailed;
+CHAR16 *gNoSubmitIfFailed;
+CHAR16 *gSaveProcess;
+CHAR16 *gSaveNoSubmitProcess;
+CHAR16 *gDiscardChange;
+CHAR16 *gJumpToFormSet;
+CHAR16 *gCheckError;
+CHAR16 *gPromptForData;
+CHAR16 *gPromptForPassword;
+CHAR16 *gPromptForNewPassword;
+CHAR16 *gConfirmPassword;
+CHAR16 *gConfirmError;
+CHAR16 *gPassowordInvalid;
+CHAR16 *gPressEnter;
+CHAR16 *gEmptyString;
+CHAR16 *gMiniString;
+CHAR16 *gOptionMismatch;
+CHAR16 *gFormSuppress;
+CHAR16 *gProtocolNotFound;
+CHAR16 *gConfirmDefaultMsg;
+CHAR16 *gConfirmSubmitMsg;
+CHAR16 *gConfirmDiscardMsg;
+CHAR16 *gConfirmResetMsg;
+CHAR16 *gConfirmExitMsg;
+CHAR16 *gConfirmSubmitMsg2nd;
+CHAR16 *gConfirmDefaultMsg2nd;
+CHAR16 *gConfirmResetMsg2nd;
+CHAR16 *gConfirmExitMsg2nd;
+CHAR16 *gConfirmOpt;
+CHAR16 *gConfirmOptYes;
+CHAR16 *gConfirmOptNo;
+CHAR16 *gConfirmOptOk;
+CHAR16 *gConfirmOptCancel;
+CHAR16 *gYesOption;
+CHAR16 *gNoOption;
+CHAR16 *gOkOption;
+CHAR16 *gCancelOption;
+CHAR16 *gErrorPopup;
+CHAR16 *gWarningPopup;
+CHAR16 *gInfoPopup;
+CHAR16 *gConfirmMsgConnect;
+CHAR16 *gConfirmMsgEnd;
+CHAR16 *gPasswordUnsupported;
+CHAR16 gModalSkipColumn;
+CHAR16 gPromptBlockWidth;
+CHAR16 gOptionBlockWidth;
+CHAR16 gHelpBlockWidth;
+CHAR16 *mUnknownString;
+
+FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {
+ FORM_DISPLAY_DRIVER_SIGNATURE,
+ NULL,
+ {
+ FormDisplay,
+ DriverClearDisplayPage,
+ ConfirmDataChange
+ },
+ {
+ EFI_HII_POPUP_PROTOCOL_REVISION,
+ CreatePopup
+ }
+};
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING String;
+
+ String = HiiGetString (HiiHandle, Token, NULL);
+ if (String == NULL) {
+ String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
+ ASSERT (String != NULL);
+ }
+
+ return (CHAR16 *)String;
+}
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeDisplayStrings (
+ VOID
+ )
+{
+ gReconnectConfirmChanges = GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES), gHiiHandle);
+ mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);
+ gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
+ gNoSubmitIfFailed = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle);
+ gReconnectFail = GetToken (STRING_TOKEN (RECONNECT_FAILED), gHiiHandle);
+ gReconnectRequired = GetToken (STRING_TOKEN (RECONNECT_REQUIRED), gHiiHandle);
+ gChangesOpt = GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS), gHiiHandle);
+ gSaveProcess = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle);
+ gSaveNoSubmitProcess = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle);
+ gDiscardChange = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle);
+ gJumpToFormSet = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle);
+ gCheckError = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle);
+ gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);
+ gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);
+ gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);
+ gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);
+ gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);
+ gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);
+ gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);
+ gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
+ gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);
+ gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);
+ gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);
+ gFormNotFound = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle);
+ gNoSubmitIf = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle);
+ gBrowserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);
+ gConfirmDefaultMsg = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE), gHiiHandle);
+ gConfirmDiscardMsg = GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE), gHiiHandle);
+ gConfirmSubmitMsg = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE), gHiiHandle);
+ gConfirmResetMsg = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE), gHiiHandle);
+ gConfirmExitMsg = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE), gHiiHandle);
+ gConfirmDefaultMsg2nd = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND), gHiiHandle);
+ gConfirmSubmitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND), gHiiHandle);
+ gConfirmResetMsg2nd = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND), gHiiHandle);
+ gConfirmExitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND), gHiiHandle);
+ gConfirmOpt = GetToken (STRING_TOKEN (CONFIRM_OPTION), gHiiHandle);
+ gConfirmOptYes = GetToken (STRING_TOKEN (CONFIRM_OPTION_YES), gHiiHandle);
+ gConfirmOptNo = GetToken (STRING_TOKEN (CONFIRM_OPTION_NO), gHiiHandle);
+ gConfirmOptOk = GetToken (STRING_TOKEN (CONFIRM_OPTION_OK), gHiiHandle);
+ gConfirmOptCancel = GetToken (STRING_TOKEN (CONFIRM_OPTION_CANCEL), gHiiHandle);
+ gYesOption = GetToken (STRING_TOKEN (YES_SELECTABLE_OPTION), gHiiHandle);
+ gNoOption = GetToken (STRING_TOKEN (NO_SELECTABLE_OPTION), gHiiHandle);
+ gOkOption = GetToken (STRING_TOKEN (OK_SELECTABLE_OPTION), gHiiHandle);
+ gCancelOption = GetToken (STRING_TOKEN (CANCEL_SELECTABLE_OPTION), gHiiHandle);
+ gErrorPopup = GetToken (STRING_TOKEN (ERROR_POPUP_STRING), gHiiHandle);
+ gWarningPopup = GetToken (STRING_TOKEN (WARNING_POPUP_STRING), gHiiHandle);
+ gInfoPopup = GetToken (STRING_TOKEN (INFO_POPUP_STRING), gHiiHandle);
+ gConfirmMsgConnect = GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT), gHiiHandle);
+ gConfirmMsgEnd = GetToken (STRING_TOKEN (CONFIRM_OPTION_END), gHiiHandle);
+ gPasswordUnsupported = GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED), gHiiHandle);
+}
+
+/**
+ Free up the resource allocated for all strings required
+ by Setup Browser.
+
+**/
+VOID
+FreeDisplayStrings (
+ VOID
+ )
+{
+ FreePool (mUnknownString);
+ FreePool (gEmptyString);
+ FreePool (gSaveFailed);
+ FreePool (gNoSubmitIfFailed);
+ FreePool (gReconnectFail);
+ FreePool (gReconnectRequired);
+ FreePool (gChangesOpt);
+ FreePool (gReconnectConfirmChanges);
+ FreePool (gSaveProcess);
+ FreePool (gSaveNoSubmitProcess);
+ FreePool (gDiscardChange);
+ FreePool (gJumpToFormSet);
+ FreePool (gCheckError);
+ FreePool (gPromptForData);
+ FreePool (gPromptForPassword);
+ FreePool (gPromptForNewPassword);
+ FreePool (gConfirmPassword);
+ FreePool (gConfirmError);
+ FreePool (gPassowordInvalid);
+ FreePool (gPressEnter);
+ FreePool (gMiniString);
+ FreePool (gOptionMismatch);
+ FreePool (gFormSuppress);
+ FreePool (gProtocolNotFound);
+ FreePool (gBrowserError);
+ FreePool (gNoSubmitIf);
+ FreePool (gFormNotFound);
+ FreePool (gConfirmDefaultMsg);
+ FreePool (gConfirmSubmitMsg);
+ FreePool (gConfirmDiscardMsg);
+ FreePool (gConfirmResetMsg);
+ FreePool (gConfirmExitMsg);
+ FreePool (gConfirmDefaultMsg2nd);
+ FreePool (gConfirmSubmitMsg2nd);
+ FreePool (gConfirmResetMsg2nd);
+ FreePool (gConfirmExitMsg2nd);
+ FreePool (gConfirmOpt);
+ FreePool (gConfirmOptYes);
+ FreePool (gConfirmOptNo);
+ FreePool (gConfirmOptOk);
+ FreePool (gConfirmOptCancel);
+ FreePool (gYesOption);
+ FreePool (gNoOption);
+ FreePool (gOkOption);
+ FreePool (gCancelOption);
+ FreePool (gErrorPopup);
+ FreePool (gWarningPopup);
+ FreePool (gInfoPopup);
+ FreePool (gConfirmMsgConnect);
+ FreePool (gConfirmMsgEnd);
+ FreePool (gPasswordUnsupported);
+}
+
+/**
+ Get prompt string id from the opcode data buffer.
+
+ @param OpCode The input opcode buffer.
+
+ @return The prompt string id.
+
+**/
+EFI_STRING_ID
+GetPrompt (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_STATEMENT_HEADER *Header;
+
+ if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {
+ return 0;
+ }
+
+ Header = (EFI_IFR_STATEMENT_HEADER *)(OpCode + 1);
+
+ return Header->Prompt;
+}
+
+/**
+ Get the supported width for a particular op-code
+
+ @param MenuOption The menu option.
+ @param AdjustWidth The width which is saved for the space.
+
+ @return Returns the number of CHAR16 characters that is support.
+
+**/
+UINT16
+GetWidth (
+ IN UI_MENU_OPTION *MenuOption,
+ OUT UINT16 *AdjustWidth
+ )
+{
+ CHAR16 *String;
+ UINTN Size;
+ EFI_IFR_TEXT *TextOp;
+ UINT16 ReturnWidth;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ Statement = MenuOption->ThisTag;
+
+ //
+ // For modal form, clean the entire row.
+ //
+ if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = LEFT_SKIPPED_COLUMNS;
+ }
+
+ return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gModalSkipColumn + LEFT_SKIPPED_COLUMNS));
+ }
+
+ Size = 0;
+
+ //
+ // See if the second text parameter is really NULL
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ TextOp = (EFI_IFR_TEXT *)Statement->OpCode;
+ if (TextOp->TextTwo != 0) {
+ String = GetToken (TextOp->TextTwo, gFormData->HiiHandle);
+ Size = StrLen (String);
+ FreePool (String);
+ }
+ }
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
+ //
+ // Allow a wide display if text op-code and no secondary text op-code
+ //
+ ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
+ )
+ {
+ //
+ // Return the space width.
+ //
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = 2;
+ }
+
+ //
+ // Keep consistent with current behavior.
+ //
+ ReturnWidth = (UINT16)(gPromptBlockWidth + gOptionBlockWidth - 2);
+ } else {
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = 1;
+ }
+
+ ReturnWidth = (UINT16)(gPromptBlockWidth - 1);
+ }
+
+ //
+ // For nest in statement, should the subtitle indent.
+ //
+ if (MenuOption->NestInStatement) {
+ ReturnWidth -= SUBTITLE_INDENT;
+ }
+
+ return ReturnWidth;
+}
+
+/**
+ Will copy LineWidth amount of a string in the OutputString buffer and return the
+ number of CHAR16 characters that were copied into the OutputString buffer.
+ The output string format is:
+ Glyph Info + String info + '\0'.
+
+ In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
+
+ @param InputString String description for this option.
+ @param LineWidth Width of the desired string to extract in CHAR16
+ characters
+ @param GlyphWidth The glyph width of the begin of the char in the string.
+ @param Index Where in InputString to start the copy process
+ @param OutputString Buffer to copy the string into
+
+ @return Returns the number of CHAR16 characters that were copied into the OutputString
+ buffer, include extra glyph info and '\0' info.
+
+**/
+UINT16
+GetLineByWidth (
+ IN CHAR16 *InputString,
+ IN UINT16 LineWidth,
+ IN OUT UINT16 *GlyphWidth,
+ IN OUT UINTN *Index,
+ OUT CHAR16 **OutputString
+ )
+{
+ UINT16 StrOffset;
+ UINT16 GlyphOffset;
+ UINT16 OriginalGlyphWidth;
+ BOOLEAN ReturnFlag;
+ UINT16 LastSpaceOffset;
+ UINT16 LastGlyphWidth;
+
+ if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) {
+ return 0;
+ }
+
+ if ((LineWidth == 0) || (*GlyphWidth == 0)) {
+ return 0;
+ }
+
+ //
+ // Save original glyph width.
+ //
+ OriginalGlyphWidth = *GlyphWidth;
+ LastGlyphWidth = OriginalGlyphWidth;
+ ReturnFlag = FALSE;
+ LastSpaceOffset = 0;
+
+ //
+ // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.
+ // To avoid displaying this empty line in screen, just skip the two CHARs here.
+ //
+ if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
+ *Index = *Index + 2;
+ }
+
+ //
+ // Fast-forward the string and see if there is a carriage-return in the string
+ //
+ for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {
+ switch (InputString[*Index + StrOffset]) {
+ case NARROW_CHAR:
+ *GlyphWidth = 1;
+ break;
+
+ case WIDE_CHAR:
+ *GlyphWidth = 2;
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ case CHAR_LINEFEED:
+ case CHAR_NULL:
+ ReturnFlag = TRUE;
+ break;
+
+ default:
+ GlyphOffset = GlyphOffset + *GlyphWidth;
+
+ //
+ // Record the last space info in this line. Will be used in rewind.
+ //
+ if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {
+ LastSpaceOffset = StrOffset;
+ LastGlyphWidth = *GlyphWidth;
+ }
+
+ break;
+ }
+
+ if (ReturnFlag) {
+ break;
+ }
+ }
+
+ //
+ // Rewind the string from the maximum size until we see a space to break the line
+ //
+ if (GlyphOffset > LineWidth) {
+ //
+ // Rewind the string to last space char in this line.
+ //
+ if (LastSpaceOffset != 0) {
+ StrOffset = LastSpaceOffset;
+ *GlyphWidth = LastGlyphWidth;
+ } else {
+ //
+ // Roll back to last char in the line width.
+ //
+ StrOffset--;
+ }
+ }
+
+ //
+ // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
+ //
+ if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) {
+ return 0;
+ }
+
+ //
+ // Need extra glyph info and '\0' info, so +2.
+ //
+ *OutputString = AllocateZeroPool ((StrOffset + 2) * sizeof (CHAR16));
+ if (*OutputString == NULL) {
+ return 0;
+ }
+
+ //
+ // Save the glyph info at the begin of the string, will used by Print function.
+ //
+ if (OriginalGlyphWidth == 1) {
+ *(*OutputString) = NARROW_CHAR;
+ } else {
+ *(*OutputString) = WIDE_CHAR;
+ }
+
+ CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof (CHAR16));
+
+ if (InputString[*Index + StrOffset] == CHAR_SPACE) {
+ //
+ // Skip the space info at the begin of next line.
+ //
+ *Index = (UINT16)(*Index + StrOffset + 1);
+ } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
+ //
+ // Skip the /n or /n/r info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
+ *Index = (UINT16)(*Index + StrOffset + 2);
+ } else {
+ *Index = (UINT16)(*Index + StrOffset + 1);
+ }
+ } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {
+ //
+ // Skip the /r or /r/n info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {
+ *Index = (UINT16)(*Index + StrOffset + 2);
+ } else {
+ *Index = (UINT16)(*Index + StrOffset + 1);
+ }
+ } else {
+ *Index = (UINT16)(*Index + StrOffset);
+ }
+
+ //
+ // Include extra glyph info and '\0' info, so +2.
+ //
+ return StrOffset + 2;
+}
+
+/**
+ Add one menu option by specified description and context.
+
+ @param Statement Statement of this Menu Option.
+ @param MenuItemCount The index for this Option in the Menu.
+ @param NestIn Whether this statement is nest in another statement.
+
+**/
+VOID
+UiAddMenuOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN UINT16 *MenuItemCount,
+ IN BOOLEAN NestIn
+ )
+{
+ UI_MENU_OPTION *MenuOption;
+ UINTN Index;
+ UINTN Count;
+ UINT16 NumberOfLines;
+ UINT16 GlyphWidth;
+ UINT16 Width;
+ UINTN ArrayEntry;
+ CHAR16 *OutputString;
+ EFI_STRING_ID PromptId;
+
+ NumberOfLines = 1;
+ ArrayEntry = 0;
+ GlyphWidth = 1;
+ Count = 1;
+ MenuOption = NULL;
+
+ PromptId = GetPrompt (Statement->OpCode);
+ ASSERT (PromptId != 0);
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ Count = 3;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
+ ASSERT (MenuOption);
+
+ MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
+ MenuOption->Description = GetToken (PromptId, gFormData->HiiHandle);
+ MenuOption->Handle = gFormData->HiiHandle;
+ MenuOption->ThisTag = Statement;
+ MenuOption->NestInStatement = NestIn;
+ MenuOption->EntryNumber = *MenuItemCount;
+
+ MenuOption->Sequence = Index;
+
+ if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {
+ MenuOption->GrayOut = TRUE;
+ } else {
+ MenuOption->GrayOut = FALSE;
+ }
+
+ if (((Statement->Attribute & HII_DISPLAY_LOCK) != 0) || ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0)) {
+ MenuOption->GrayOut = TRUE;
+ }
+
+ //
+ // If the form or the question has the lock attribute, deal same as grayout.
+ //
+ if (((gFormData->Attribute & HII_DISPLAY_LOCK) != 0) || ((Statement->Attribute & HII_DISPLAY_LOCK) != 0)) {
+ MenuOption->GrayOut = TRUE;
+ }
+
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_TIME_OP:
+ case EFI_IFR_DATE_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_PASSWORD_OP:
+ case EFI_IFR_STRING_OP:
+ //
+ // User could change the value of these items
+ //
+ MenuOption->IsQuestion = TRUE;
+ break;
+ case EFI_IFR_TEXT_OP:
+ if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {
+ //
+ // Initializing GrayOut option as TRUE for Text setup options
+ // so that those options will be Gray in colour and un selectable.
+ //
+ MenuOption->GrayOut = TRUE;
+ }
+
+ break;
+ default:
+ MenuOption->IsQuestion = FALSE;
+ break;
+ }
+
+ if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {
+ MenuOption->ReadOnly = TRUE;
+ if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {
+ MenuOption->GrayOut = TRUE;
+ }
+ }
+
+ if ((Index == 0) &&
+ (Statement->OpCode->OpCode != EFI_IFR_DATE_OP) &&
+ (Statement->OpCode->OpCode != EFI_IFR_TIME_OP))
+ {
+ Width = GetWidth (MenuOption, NULL);
+ for ( ; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &ArrayEntry, &OutputString) != 0x0000;) {
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&MenuOption->Description[ArrayEntry]) != 0) {
+ NumberOfLines++;
+ }
+
+ FreePool (OutputString);
+ }
+ } else {
+ //
+ // Add three MenuOptions for Date/Time
+ // Data format : [01/02/2004] [11:22:33]
+ // Line number : 0 0 1 0 0 1
+ //
+ NumberOfLines = 0;
+ }
+
+ if (Index == 2) {
+ //
+ // Override LineNumber for the MenuOption in Date/Time sequence
+ //
+ MenuOption->Skip = 1;
+ } else {
+ MenuOption->Skip = NumberOfLines;
+ }
+
+ InsertTailList (&gMenuOption, &MenuOption->Link);
+ }
+
+ (*MenuItemCount)++;
+}
+
+/**
+ Create the menu list base on the form data info.
+
+**/
+VOID
+ConvertStatementToMenu (
+ VOID
+ )
+{
+ UINT16 MenuItemCount;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NestLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
+
+ MenuItemCount = 0;
+ InitializeListHead (&gMenuOption);
+
+ Link = GetFirstNode (&gFormData->StatementListHead);
+ while (!IsNull (&gFormData->StatementListHead, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gFormData->StatementListHead, Link);
+
+ //
+ // Skip the opcode not recognized by Display core.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {
+ continue;
+ }
+
+ UiAddMenuOption (Statement, &MenuItemCount, FALSE);
+
+ //
+ // Check the statement nest in this host statement.
+ //
+ NestLink = GetFirstNode (&Statement->NestStatementList);
+ while (!IsNull (&Statement->NestStatementList, NestLink)) {
+ NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
+ NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
+
+ //
+ // Skip the opcode not recognized by Display core.
+ //
+ if (NestStatement->OpCode->OpCode == EFI_IFR_GUID_OP) {
+ continue;
+ }
+
+ UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);
+ }
+ }
+}
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+GetStringWidth (
+ IN CHAR16 *String
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN IncrementValue;
+
+ ASSERT (String != NULL);
+ if (String == NULL) {
+ return 0;
+ }
+
+ Index = 0;
+ Count = 0;
+ IncrementValue = 1;
+
+ do {
+ //
+ // Advance to the null-terminator or to the first width directive
+ //
+ for ( ;
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
+ Index++, Count = Count + IncrementValue
+ )
+ {
+ }
+
+ //
+ // We hit the null-terminator, we now have a count
+ //
+ if (String[Index] == 0) {
+ break;
+ }
+
+ //
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
+ //
+ if (String[Index] == NARROW_CHAR) {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 1;
+ } else {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 2;
+ }
+ } while (String[Index] != 0);
+
+ //
+ // Increment by one to include the null-terminator in the size
+ //
+ Count++;
+
+ return Count * sizeof (CHAR16);
+}
+
+/**
+ Base on the input option string to update the skip value for a menu option.
+
+ @param MenuOption The MenuOption to be checked.
+ @param OptionString The input option string.
+
+**/
+VOID
+UpdateSkipInfoForMenu (
+ IN UI_MENU_OPTION *MenuOption,
+ IN CHAR16 *OptionString
+ )
+{
+ UINTN Index;
+ UINT16 Width;
+ UINTN Row;
+ CHAR16 *OutputString;
+ UINT16 GlyphWidth;
+
+ Width = (UINT16)gOptionBlockWidth - 1;
+ GlyphWidth = 1;
+ Row = 1;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if (StrLen (&OptionString[Index]) != 0) {
+ Row++;
+ }
+
+ FreePool (OutputString);
+ }
+
+ if ((Row > MenuOption->Skip) &&
+ (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) &&
+ (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP))
+ {
+ MenuOption->Skip = Row;
+ }
+}
+
+/**
+ Update display lines for a Menu Option.
+
+ @param MenuOption The MenuOption to be checked.
+
+**/
+VOID
+UpdateOptionSkipLines (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ CHAR16 *OptionString;
+
+ OptionString = NULL;
+
+ ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
+ if (OptionString != NULL) {
+ UpdateSkipInfoForMenu (MenuOption, OptionString);
+
+ FreePool (OptionString);
+ }
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
+ OptionString = GetToken (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
+
+ if (OptionString != NULL) {
+ UpdateSkipInfoForMenu (MenuOption, OptionString);
+
+ FreePool (OptionString);
+ }
+ }
+}
+
+/**
+ Check whether this Menu Option could be print.
+
+ Check Prompt string, option string or text two string not NULL.
+
+ This is an internal function.
+
+ @param MenuOption The MenuOption to be checked.
+
+ @retval TRUE This Menu Option is printable.
+ @retval FALSE This Menu Option could not be printable.
+
+**/
+BOOLEAN
+PrintableMenu (
+ UI_MENU_OPTION *MenuOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING OptionString;
+
+ OptionString = NULL;
+
+ if (MenuOption->Description[0] != '\0') {
+ return TRUE;
+ }
+
+ Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((OptionString != NULL) && (OptionString[0] != '\0')) {
+ FreePool (OptionString);
+ return TRUE;
+ }
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
+ OptionString = GetToken (((EFI_IFR_TEXT *)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
+ ASSERT (OptionString != NULL);
+ if (OptionString[0] != '\0') {
+ FreePool (OptionString);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether this Menu Option could be highlighted.
+
+ This is an internal function.
+
+ @param MenuOption The MenuOption to be checked.
+
+ @retval TRUE This Menu Option is selectable.
+ @retval FALSE This Menu Option could not be selected.
+
+**/
+BOOLEAN
+IsSelectable (
+ UI_MENU_OPTION *MenuOption
+ )
+{
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ MenuOption->GrayOut || MenuOption->ReadOnly || !PrintableMenu (MenuOption))
+ {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Move to next selectable statement.
+
+ This is an internal function.
+
+ @param GoUp The navigation direction. TRUE: up, FALSE: down.
+ @param CurrentPosition Current position.
+ @param GapToTop Gap position to top or bottom.
+ @param FindInForm Whether find menu in current form or beyond.
+
+ @return The row distance from current MenuOption to next selectable MenuOption.
+
+ @retval -1 Reach the begin of the menu, still can't find the selectable menu.
+ @retval Value Find the selectable menu, maybe the truly selectable, maybe the
+ first menu showing beyond current form or last menu showing in
+ current form.
+ The value is the line number between the new selected menu and the
+ current select menu, not include the new selected menu.
+
+**/
+INTN
+MoveToNextStatement (
+ IN BOOLEAN GoUp,
+ IN OUT LIST_ENTRY **CurrentPosition,
+ IN UINTN GapToTop,
+ IN BOOLEAN FindInForm
+ )
+{
+ INTN Distance;
+ LIST_ENTRY *Pos;
+ UI_MENU_OPTION *NextMenuOption;
+ UI_MENU_OPTION *PreMenuOption;
+
+ Distance = 0;
+ Pos = *CurrentPosition;
+
+ if (Pos == &gMenuOption) {
+ return -1;
+ }
+
+ PreMenuOption = MENU_OPTION_FROM_LINK (Pos);
+
+ while (TRUE) {
+ NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
+ //
+ // NextMenuOption->Row == 0 means this menu has not calculate
+ // the NextMenuOption->Skip value yet, just calculate here.
+ //
+ if (NextMenuOption->Row == 0) {
+ UpdateOptionSkipLines (NextMenuOption);
+ }
+
+ //
+ // Check whether the menu is beyond current showing form,
+ // return the first one beyond the showing form.
+ //
+ if ((UINTN)Distance + NextMenuOption->Skip > GapToTop) {
+ if (FindInForm) {
+ NextMenuOption = PreMenuOption;
+ }
+
+ break;
+ }
+
+ //
+ // return the selectable menu in the showing form.
+ //
+ if (IsSelectable (NextMenuOption)) {
+ break;
+ }
+
+ Distance += NextMenuOption->Skip;
+
+ //
+ // Arrive at begin of the menu list.
+ //
+ if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {
+ Distance = -1;
+ break;
+ }
+
+ Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
+ PreMenuOption = NextMenuOption;
+ }
+
+ *CurrentPosition = &NextMenuOption->Link;
+ return Distance;
+}
+
+/**
+ Process option string for date/time opcode.
+
+ @param MenuOption Menu option point to date/time.
+ @param OptionString Option string input for process.
+ @param AddOptCol Whether need to update MenuOption->OptCol.
+
+**/
+VOID
+ProcessStringForDateTime (
+ UI_MENU_OPTION *MenuOption,
+ CHAR16 *OptionString,
+ BOOLEAN AddOptCol
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ EFI_IFR_DATE *Date;
+ EFI_IFR_TIME *Time;
+
+ ASSERT (MenuOption != NULL && OptionString != NULL);
+
+ Statement = MenuOption->ThisTag;
+ Date = NULL;
+ Time = NULL;
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ Date = (EFI_IFR_DATE *)Statement->OpCode;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ Time = (EFI_IFR_TIME *)Statement->OpCode;
+ }
+
+ //
+ // If leading spaces on OptionString - remove the spaces
+ //
+ for (Index = 0; OptionString[Index] == L' '; Index++) {
+ //
+ // Base on the blockspace to get the option column info.
+ //
+ if (AddOptCol) {
+ MenuOption->OptCol++;
+ }
+ }
+
+ for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
+ OptionString[Count] = OptionString[Index];
+ Count++;
+ }
+
+ OptionString[Count] = CHAR_NULL;
+
+ //
+ // Enable to suppress field in the opcode base on the flag.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ //
+ // OptionString format is: <**: **: ****>
+ // |month|day|year|
+ // 4 3 5
+ //
+ if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {
+ //
+ // At this point, only "<**:" in the optionstring.
+ // Clean the day's ** field, after clean, the format is "< :"
+ //
+ SetUnicodeMem (&OptionString[1], 2, L' ');
+ } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {
+ //
+ // At this point, only "**:" in the optionstring.
+ // Clean the month's "**" field, after clean, the format is " :"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {
+ //
+ // At this point, only "****>" in the optionstring.
+ // Clean the year's "****" field, after clean, the format is " >"
+ //
+ SetUnicodeMem (&OptionString[0], 4, L' ');
+ }
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ //
+ // OptionString format is: <**: **: **>
+ // |hour|minute|second|
+ // 4 3 3
+ //
+ if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {
+ //
+ // At this point, only "<**:" in the optionstring.
+ // Clean the hour's ** field, after clean, the format is "< :"
+ //
+ SetUnicodeMem (&OptionString[1], 2, L' ');
+ } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {
+ //
+ // At this point, only "**:" in the optionstring.
+ // Clean the minute's "**" field, after clean, the format is " :"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {
+ //
+ // At this point, only "**>" in the optionstring.
+ // Clean the second's "**" field, after clean, the format is " >"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ }
+ }
+}
+
+/**
+ Adjust Data and Time position accordingly.
+ Data format : [01/02/2004] [11:22:33]
+ Line number : 0 0 1 0 0 1
+
+ This is an internal function.
+
+ @param DirectionUp the up or down direction. False is down. True is
+ up.
+ @param CurrentPosition Current position. On return: Point to the last
+ Option (Year or Second) if up; Point to the first
+ Option (Month or Hour) if down.
+
+ @return Return line number to pad. It is possible that we stand on a zero-advance
+ @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
+
+**/
+UINTN
+AdjustDateAndTimePosition (
+ IN BOOLEAN DirectionUp,
+ IN OUT LIST_ENTRY **CurrentPosition
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *NewPosition;
+ UI_MENU_OPTION *MenuOption;
+ UINTN PadLineNumber;
+
+ PadLineNumber = 0;
+ NewPosition = *CurrentPosition;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP))
+ {
+ //
+ // Calculate the distance from current position to the last Date/Time MenuOption
+ //
+ Count = 0;
+ while (MenuOption->Skip == 0) {
+ Count++;
+ NewPosition = NewPosition->ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
+ PadLineNumber = 1;
+ }
+
+ NewPosition = *CurrentPosition;
+ if (DirectionUp) {
+ //
+ // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
+ // to be one that back to the previous set of MenuOptions, we need to advance to the first
+ // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
+ // checking can be done.
+ //
+ while (Count++ < 2) {
+ NewPosition = NewPosition->BackLink;
+ }
+ } else {
+ //
+ // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
+ // to be one that progresses to the next set of MenuOptions, we need to advance to the last
+ // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
+ // checking can be done.
+ //
+ while (Count-- > 0) {
+ NewPosition = NewPosition->ForwardLink;
+ }
+ }
+
+ *CurrentPosition = NewPosition;
+ }
+
+ return PadLineNumber;
+}
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+GetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_NUMERIC *NumericOp;
+ UINT64 Step;
+
+ NumericOp = (EFI_IFR_NUMERIC *)OpCode;
+
+ switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ Step = NumericOp->data.u8.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ Step = NumericOp->data.u16.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ Step = NumericOp->data.u32.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ Step = NumericOp->data.u64.Step;
+ break;
+
+ default:
+ Step = 0;
+ break;
+ }
+
+ return Step;
+}
+
+/**
+ Find the registered HotKey based on KeyData.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key.
+
+ @return The registered HotKey context. If no found, NULL will return.
+**/
+BROWSER_HOT_KEY *
+GetHotKeyFromRegisterList (
+ IN EFI_INPUT_KEY *KeyData
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_HOT_KEY *HotKey;
+
+ Link = GetFirstNode (&gFormData->HotKeyListHead);
+ while (!IsNull (&gFormData->HotKeyListHead, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+
+ if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
+ return HotKey;
+ }
+
+ Link = GetNextNode (&gFormData->HotKeyListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Determine if the menu is the last menu that can be selected.
+
+ This is an internal function.
+
+ @param Direction The scroll direction. False is down. True is up.
+ @param CurrentPos The current focus.
+
+ @return FALSE -- the menu isn't the last menu that can be selected.
+ @return TRUE -- the menu is the last menu that can be selected.
+
+**/
+BOOLEAN
+ValueIsScroll (
+ IN BOOLEAN Direction,
+ IN LIST_ENTRY *CurrentPos
+ )
+{
+ LIST_ENTRY *Temp;
+
+ Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
+
+ if (Temp == &gMenuOption) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Wait for a given event to fire, or for an optional timeout to expire.
+
+ @param Event The event to wait for
+
+ @retval UI_EVENT_TYPE The type of the event which is trigged.
+
+**/
+UI_EVENT_TYPE
+UiWaitForEvent (
+ IN EFI_EVENT Event
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN EventNum;
+ UINT64 Timeout;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[3];
+ UI_EVENT_TYPE EventType;
+
+ TimerEvent = NULL;
+ Timeout = FormExitTimeout (gFormData);
+
+ if (Timeout != 0) {
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+
+ //
+ // Set the timer event
+ //
+ gBS->SetTimer (
+ TimerEvent,
+ TimerRelative,
+ Timeout
+ );
+ }
+
+ WaitList[0] = Event;
+ EventNum = 1;
+ if (gFormData->FormRefreshEvent != NULL) {
+ WaitList[EventNum] = gFormData->FormRefreshEvent;
+ EventNum++;
+ }
+
+ if (Timeout != 0) {
+ WaitList[EventNum] = TimerEvent;
+ EventNum++;
+ }
+
+ Status = gBS->WaitForEvent (EventNum, WaitList, &Index);
+ ASSERT_EFI_ERROR (Status);
+
+ switch (Index) {
+ case 0:
+ EventType = UIEventKey;
+ break;
+
+ case 1:
+ if (gFormData->FormRefreshEvent != NULL) {
+ EventType = UIEventDriver;
+ } else {
+ ASSERT (Timeout != 0 && EventNum == 2);
+ EventType = UIEventTimeOut;
+ }
+
+ break;
+
+ default:
+ ASSERT (Index == 2 && EventNum == 3);
+ EventType = UIEventTimeOut;
+ break;
+ }
+
+ if (Timeout != 0) {
+ gBS->CloseEvent (TimerEvent);
+ }
+
+ return EventType;
+}
+
+/**
+ Get question id info from the input opcode header.
+
+ @param OpCode The input opcode header pointer.
+
+ @retval The question id for this opcode.
+
+**/
+EFI_QUESTION_ID
+GetQuestionIdInfo (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_QUESTION_HEADER *QuestionHeader;
+
+ if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {
+ return 0;
+ }
+
+ QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *)OpCode + sizeof (EFI_IFR_OP_HEADER));
+
+ return QuestionHeader->QuestionId;
+}
+
+/**
+ Find the top of screen menu base on the current menu.
+
+ @param CurPos Current input menu.
+ @param Rows Totol screen rows.
+ @param SkipValue SkipValue for this new form.
+
+ @retval TopOfScreen Top of screen menu for the new form.
+
+**/
+LIST_ENTRY *
+FindTopOfScreenMenu (
+ IN LIST_ENTRY *CurPos,
+ IN UINTN Rows,
+ OUT UINTN *SkipValue
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *TopOfScreen;
+ UI_MENU_OPTION *PreviousMenuOption;
+
+ Link = CurPos;
+ PreviousMenuOption = NULL;
+
+ while (Link->BackLink != &gMenuOption) {
+ Link = Link->BackLink;
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
+ if (PreviousMenuOption->Row == 0) {
+ UpdateOptionSkipLines (PreviousMenuOption);
+ }
+
+ if (Rows <= PreviousMenuOption->Skip) {
+ break;
+ }
+
+ Rows = Rows - PreviousMenuOption->Skip;
+ }
+
+ if (Link->BackLink == &gMenuOption) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ if ((PreviousMenuOption != NULL) && (Rows < PreviousMenuOption->Skip)) {
+ *SkipValue = PreviousMenuOption->Skip - Rows;
+ } else {
+ *SkipValue = 0;
+ }
+ } else {
+ TopOfScreen = Link;
+ *SkipValue = PreviousMenuOption->Skip - Rows;
+ }
+
+ return TopOfScreen;
+}
+
+/**
+ Get the index info for this opcode.
+
+ @param OpCode The input opcode for the statement.
+
+ @retval The index of this statement.
+
+**/
+UINTN
+GetIndexInfoForOpcode (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+ UINTN Index;
+
+ NewPos = gMenuOption.ForwardLink;
+ Index = 0;
+
+ for (NewPos = gMenuOption.ForwardLink; NewPos != &gMenuOption; NewPos = NewPos->ForwardLink) {
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (CompareMem (MenuOption->ThisTag->OpCode, OpCode, OpCode->Length) == 0) {
+ if (MenuOption->ThisTag->OpCode == OpCode) {
+ return Index;
+ }
+
+ Index++;
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Is this the saved highlight statement.
+
+ @param HighLightedStatement The input highlight statement.
+
+ @retval TRUE This is the highlight statement.
+ @retval FALSE This is not the highlight statement.
+
+**/
+BOOLEAN
+IsSavedHighlightStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
+ )
+{
+ if ((gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) &&
+ (gFormData->FormId == gHighligthMenuInfo.FormId))
+ {
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {
+ return (BOOLEAN)(gHighligthMenuInfo.HLTQuestionId == GetQuestionIdInfo (HighLightedStatement->OpCode));
+ } else {
+ if (CompareMem (gHighligthMenuInfo.HLTOpCode, HighLightedStatement->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
+ if ((gHighligthMenuInfo.HLTIndex == 0) || (gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode (HighLightedStatement->OpCode))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Is this the highlight menu.
+
+ @param MenuOption The input Menu option.
+
+ @retval TRUE This is the highlight menu option.
+ @retval FALSE This is not the highlight menu option.
+
+**/
+BOOLEAN
+IsHighLightMenuOption (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {
+ if (GetQuestionIdInfo (MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.HLTQuestionId) {
+ return (BOOLEAN)(MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
+ }
+ } else {
+ if (CompareMem (gHighligthMenuInfo.HLTOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
+ if ((gHighligthMenuInfo.HLTIndex == 0) || (gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode (MenuOption->ThisTag->OpCode))) {
+ return (BOOLEAN)(MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
+ } else {
+ return FALSE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Find the highlight menu.
+
+ If the input is NULL, base on the record highlight info in
+ gHighligthMenuInfo to find the last highlight menu.
+
+ @param HighLightedStatement The input highlight statement.
+
+ @retval The highlight menu index.
+
+**/
+LIST_ENTRY *
+FindHighLightMenuOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+
+ NewPos = gMenuOption.ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (HighLightedStatement != NULL) {
+ while (MenuOption->ThisTag != HighLightedStatement) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Must find the highlight statement.
+ //
+ ASSERT (NewPos != &gMenuOption);
+ } else {
+ while (!IsHighLightMenuOption (MenuOption)) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Highlight statement has disappear (suppressed/disableed)
+ //
+ if (NewPos == &gMenuOption) {
+ NewPos = NULL;
+ }
+ }
+
+ return NewPos;
+}
+
+/**
+ Is this the Top of screen menu.
+
+ @param MenuOption The input Menu option.
+
+ @retval TRUE This is the Top of screen menu option.
+ @retval FALSE This is not the Top of screen menu option.
+
+**/
+BOOLEAN
+IsTopOfScreeMenuOption (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ if (gHighligthMenuInfo.TOSQuestionId != 0) {
+ return (BOOLEAN)(GetQuestionIdInfo (MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.TOSQuestionId);
+ }
+
+ if (CompareMem (gHighligthMenuInfo.TOSOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.TOSOpCode->Length) == 0) {
+ if ((gHighligthMenuInfo.TOSIndex == 0) || (gHighligthMenuInfo.TOSIndex == GetIndexInfoForOpcode (MenuOption->ThisTag->OpCode))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Calculate the distance between two menus and include the skip value of StartMenu.
+
+ @param StartMenu The link_entry pointer to start menu.
+ @param EndMenu The link_entry pointer to end menu.
+
+**/
+UINTN
+GetDistanceBetweenMenus (
+ IN LIST_ENTRY *StartMenu,
+ IN LIST_ENTRY *EndMenu
+ )
+{
+ LIST_ENTRY *Link;
+ UI_MENU_OPTION *MenuOption;
+ UINTN Distance;
+
+ Distance = 0;
+
+ Link = StartMenu;
+ while (Link != EndMenu) {
+ MenuOption = MENU_OPTION_FROM_LINK (Link);
+ if (MenuOption->Row == 0) {
+ UpdateOptionSkipLines (MenuOption);
+ }
+
+ Distance += MenuOption->Skip;
+ Link = Link->BackLink;
+ }
+
+ return Distance;
+}
+
+/**
+ Find the top of screen menu base on the previous record menu info.
+
+ @param HighLightMenu The link_entry pointer to highlight menu.
+
+ @retval Return the the link_entry pointer top of screen menu.
+
+**/
+LIST_ENTRY *
+FindTopOfScreenMenuOption (
+ IN LIST_ENTRY *HighLightMenu
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+ UINTN TopRow;
+ UINTN BottomRow;
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
+
+ NewPos = gMenuOption.ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ while (!IsTopOfScreeMenuOption (MenuOption)) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Last time top of screen menu has disappeared.
+ //
+ if (NewPos == &gMenuOption) {
+ return NULL;
+ }
+
+ //
+ // Check whether highlight menu and top of screen menu can be shown within one page,
+ // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
+ // may be dynamically inserted between highlightmenu and previous top of screen menu,
+ // So previous record top of screen menu is not appropriate for current display.
+ //
+ if (GetDistanceBetweenMenus (HighLightMenu, NewPos) + 1 > BottomRow - TopRow) {
+ return NULL;
+ }
+
+ return NewPos;
+}
+
+/**
+ Find the first menu which will be show at the top.
+
+ @param FormData The data info for this form.
+ @param TopOfScreen The link_entry pointer to top menu.
+ @param HighlightMenu The menu which will be highlight.
+ @param SkipValue The skip value for the top menu.
+
+**/
+VOID
+FindTopMenu (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT LIST_ENTRY **TopOfScreen,
+ OUT LIST_ENTRY **HighlightMenu,
+ OUT UINTN *SkipValue
+ )
+{
+ UINTN TopRow;
+ UINTN BottomRow;
+ UI_MENU_OPTION *MenuOption;
+ UINTN TmpValue;
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
+ //
+ // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
+ // and the other is exit current form and enter last form, it can be covered by the else case.
+ //
+ if (gMisMatch && (gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) && (gFormData->FormId == gHighligthMenuInfo.FormId)) {
+ //
+ // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
+ // base on the record highlight info to find the highlight menu.
+ //
+
+ *HighlightMenu = FindHighLightMenuOption (NULL);
+ if (*HighlightMenu != NULL) {
+ //
+ // Update skip info for this highlight menu.
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ //
+ // Found the last time highlight menu.
+ //
+ *TopOfScreen = FindTopOfScreenMenuOption (*HighlightMenu);
+ if (*TopOfScreen != NULL) {
+ //
+ // Found the last time selectable top of screen menu.
+ //
+ AdjustDateAndTimePosition (TRUE, TopOfScreen);
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
+ UpdateOptionSkipLines (MenuOption);
+
+ *SkipValue = gHighligthMenuInfo.SkipValue;
+ } else {
+ //
+ // Not found last time top of screen menu, so base on current highlight menu
+ // to find the new top of screen menu.
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ }
+ } else {
+ //
+ // Last time highlight menu has disappear, find the first highlightable menu as the default one.
+ //
+ *HighlightMenu = gMenuOption.ForwardLink;
+ if (!IsListEmpty (&gMenuOption)) {
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
+ }
+
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *SkipValue = 0;
+ }
+ } else if (FormData->HighLightedStatement != NULL) {
+ if (IsSavedHighlightStatement (FormData->HighLightedStatement)) {
+ //
+ // Input highlight menu is same as last time highlight menu.
+ // Base on last time highlight menu to set the top of screen menu and highlight menu.
+ //
+ *HighlightMenu = FindHighLightMenuOption (NULL);
+ ASSERT (*HighlightMenu != NULL);
+
+ //
+ // Update skip info for this highlight menu.
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ *TopOfScreen = FindTopOfScreenMenuOption (*HighlightMenu);
+ if (*TopOfScreen == NULL) {
+ //
+ // Not found last time top of screen menu, so base on current highlight menu
+ // to find the new top of screen menu.
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ } else {
+ AdjustDateAndTimePosition (TRUE, TopOfScreen);
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
+ UpdateOptionSkipLines (MenuOption);
+
+ *SkipValue = gHighligthMenuInfo.SkipValue;
+ }
+
+ AdjustDateAndTimePosition (TRUE, TopOfScreen);
+ } else {
+ //
+ // Input highlight menu is not save as last time highlight menu.
+ //
+ *HighlightMenu = FindHighLightMenuOption (FormData->HighLightedStatement);
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ //
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu (*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ }
+
+ AdjustDateAndTimePosition (TRUE, TopOfScreen);
+ } else {
+ //
+ // If not has input highlight statement, just return the first one in this form.
+ //
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *HighlightMenu = gMenuOption.ForwardLink;
+ if (!IsListEmpty (&gMenuOption)) {
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
+ }
+
+ *SkipValue = 0;
+ }
+
+ gMisMatch = FALSE;
+
+ //
+ // First enter to show the menu, update highlight info.
+ //
+ UpdateHighlightMenuInfo (*HighlightMenu, *TopOfScreen, *SkipValue);
+}
+
+/**
+ Record the highlight menu and top of screen menu info.
+
+ @param Highlight The menu opton which is highlight.
+ @param TopOfScreen The menu opton which is at the top of the form.
+ @param SkipValue The skip line info for the top of screen menu.
+
+**/
+VOID
+UpdateHighlightMenuInfo (
+ IN LIST_ENTRY *Highlight,
+ IN LIST_ENTRY *TopOfScreen,
+ IN UINTN SkipValue
+ )
+{
+ UI_MENU_OPTION *MenuOption;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ gHighligthMenuInfo.HiiHandle = gFormData->HiiHandle;
+ gHighligthMenuInfo.FormId = gFormData->FormId;
+ gHighligthMenuInfo.SkipValue = (UINT16)SkipValue;
+
+ if (!IsListEmpty (&gMenuOption)) {
+ MenuOption = MENU_OPTION_FROM_LINK (Highlight);
+ Statement = MenuOption->ThisTag;
+
+ gUserInput->SelectedStatement = Statement;
+
+ gHighligthMenuInfo.HLTSequence = MenuOption->Sequence;
+ gHighligthMenuInfo.HLTQuestionId = GetQuestionIdInfo (Statement->OpCode);
+ if (gHighligthMenuInfo.HLTQuestionId == 0) {
+ //
+ // if question id == 0, save the opcode buffer..
+ //
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+
+ gHighligthMenuInfo.HLTOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
+ ASSERT (gHighligthMenuInfo.HLTOpCode != NULL);
+
+ gHighligthMenuInfo.HLTIndex = GetIndexInfoForOpcode (Statement->OpCode);
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+ Statement = MenuOption->ThisTag;
+
+ gHighligthMenuInfo.TOSQuestionId = GetQuestionIdInfo (Statement->OpCode);
+ if (gHighligthMenuInfo.TOSQuestionId == 0) {
+ //
+ // if question id == 0, save the opcode buffer..
+ //
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+
+ gHighligthMenuInfo.TOSOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
+ ASSERT (gHighligthMenuInfo.TOSOpCode != NULL);
+
+ gHighligthMenuInfo.TOSIndex = GetIndexInfoForOpcode (Statement->OpCode);
+ }
+ } else {
+ gUserInput->SelectedStatement = NULL;
+
+ gHighligthMenuInfo.HLTSequence = 0;
+ gHighligthMenuInfo.HLTQuestionId = 0;
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+
+ gHighligthMenuInfo.HLTOpCode = NULL;
+ gHighligthMenuInfo.HLTIndex = 0;
+
+ gHighligthMenuInfo.TOSQuestionId = 0;
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+
+ gHighligthMenuInfo.TOSOpCode = NULL;
+ gHighligthMenuInfo.TOSIndex = 0;
+ }
+}
+
+/**
+ Update attribut for this menu.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param Highlight Whether this menu will be highlight.
+
+**/
+VOID
+SetDisplayAttribute (
+ IN UI_MENU_OPTION *MenuOption,
+ IN BOOLEAN Highlight
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ Statement = MenuOption->ThisTag;
+
+ if (Highlight) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+ return;
+ }
+
+ if (MenuOption->GrayOut) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
+ } else {
+ if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+ }
+}
+
+/**
+ Print string for this menu option.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param Col The column that this string will be print at.
+ @param Row The row that this string will be print at.
+ @param String The string which need to print.
+ @param Width The width need to print, if string is less than the
+ width, the block space will be used.
+ @param Highlight Whether this menu will be highlight.
+
+**/
+VOID
+DisplayMenuString (
+ IN UI_MENU_OPTION *MenuOption,
+ IN UINTN Col,
+ IN UINTN Row,
+ IN CHAR16 *String,
+ IN UINTN Width,
+ IN BOOLEAN Highlight
+ )
+{
+ UINTN Length;
+
+ //
+ // Print string with normal color.
+ //
+ if (!Highlight) {
+ PrintStringAtWithWidth (Col, Row, String, Width);
+ return;
+ }
+
+ //
+ // Print the highlight menu string.
+ // First print the highlight string.
+ //
+ SetDisplayAttribute (MenuOption, TRUE);
+ Length = PrintStringAt (Col, Row, String);
+
+ //
+ // Second, clean the empty after the string.
+ //
+ SetDisplayAttribute (MenuOption, FALSE);
+ PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);
+}
+
+/**
+ Check whether this menu can has option string.
+
+ @param MenuOption The menu opton which this attribut used to.
+
+ @retval TRUE This menu option can have option string.
+ @retval FALSE This menu option can't have option string.
+
+**/
+BOOLEAN
+HasOptionString (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ CHAR16 *String;
+ UINTN Size;
+ EFI_IFR_TEXT *TextOp;
+
+ Size = 0;
+ Statement = MenuOption->ThisTag;
+
+ //
+ // See if the second text parameter is really NULL
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ TextOp = (EFI_IFR_TEXT *)Statement->OpCode;
+ if (TextOp->TextTwo != 0) {
+ String = GetToken (TextOp->TextTwo, gFormData->HiiHandle);
+ Size = StrLen (String);
+ FreePool (String);
+ }
+ }
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
+ //
+ // Allow a wide display if text op-code and no secondary text op-code
+ //
+ ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
+ )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Double confirm with user about the action.
+
+ @param Action The user input action.
+
+ @retval TRUE User confirm with the input or not need user confirm.
+ @retval FALSE User want ignore this input.
+
+**/
+BOOLEAN
+FxConfirmPopup (
+ IN UINT32 Action
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *CfmStr;
+ UINTN CfmStrLen;
+ UINT32 CheckFlags;
+ BOOLEAN RetVal;
+ UINTN CatLen;
+ UINTN MaxLen;
+
+ CfmStrLen = 0;
+ CatLen = StrLen (gConfirmMsgConnect);
+
+ //
+ // Below action need extra popup dialog to confirm.
+ //
+ CheckFlags = BROWSER_ACTION_DISCARD |
+ BROWSER_ACTION_DEFAULT |
+ BROWSER_ACTION_SUBMIT |
+ BROWSER_ACTION_RESET |
+ BROWSER_ACTION_EXIT;
+
+ //
+ // Not need to confirm with user, just return TRUE.
+ //
+ if ((Action & CheckFlags) == 0) {
+ return TRUE;
+ }
+
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ CfmStrLen += StrLen (gConfirmDiscardMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmDefaultMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmSubmitMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmResetMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmExitMsg);
+ }
+
+ //
+ // Allocate buffer to save the string.
+ // String + "?" + "\0"
+ //
+ MaxLen = CfmStrLen + 1 + 1;
+ CfmStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (CfmStr != NULL);
+
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ StrCpyS (CfmStr, MaxLen, gConfirmDiscardMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmDefaultMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmDefaultMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmSubmitMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmSubmitMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmResetMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmResetMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmExitMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmExitMsg);
+ }
+ }
+
+ StrCatS (CfmStr, MaxLen, gConfirmMsgEnd);
+
+ do {
+ CreateDialog (&Key, gEmptyString, CfmStr, gConfirmOpt, gEmptyString, NULL);
+ } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptNo[0] | UPPER_LOWER_CASE_OFFSET)) &&
+ (Key.ScanCode != SCAN_ESC));
+
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) {
+ RetVal = TRUE;
+ } else {
+ RetVal = FALSE;
+ }
+
+ FreePool (CfmStr);
+
+ return RetVal;
+}
+
+/**
+ Print string for this menu option.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param SkipWidth The skip width between the left to the start of the prompt.
+ @param BeginCol The begin column for one menu.
+ @param SkipLine The skip line for this menu.
+ @param BottomRow The bottom row for this form.
+ @param Highlight Whether this menu will be highlight.
+ @param UpdateCol Whether need to update the column info for Date/Time.
+
+ @retval EFI_SUCESSS Process the user selection success.
+
+**/
+EFI_STATUS
+DisplayOneMenu (
+ IN UI_MENU_OPTION *MenuOption,
+ IN UINTN SkipWidth,
+ IN UINTN BeginCol,
+ IN UINTN SkipLine,
+ IN UINTN BottomRow,
+ IN BOOLEAN Highlight,
+ IN BOOLEAN UpdateCol
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ UINTN Index;
+ UINT16 Width;
+ UINT16 PromptWidth;
+ CHAR16 *StringPtr;
+ CHAR16 *OptionString;
+ CHAR16 *OutputString;
+ UINT16 GlyphWidth;
+ UINTN Temp;
+ UINTN Temp2;
+ UINTN Temp3;
+ EFI_STATUS Status;
+ UINTN Row;
+ BOOLEAN IsProcessingFirstRow;
+ UINTN Col;
+ UINTN PromptLineNum;
+ UINTN OptionLineNum;
+ CHAR16 AdjustValue;
+ UINTN MaxRow;
+
+ Statement = MenuOption->ThisTag;
+ Temp = SkipLine;
+ Temp2 = SkipLine;
+ Temp3 = SkipLine;
+ AdjustValue = 0;
+ PromptLineNum = 0;
+ OptionLineNum = 0;
+ MaxRow = 0;
+ IsProcessingFirstRow = TRUE;
+
+ //
+ // Set default color.
+ //
+ SetDisplayAttribute (MenuOption, FALSE);
+
+ //
+ // 1. Paint the option string.
+ //
+ Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (OptionString != NULL) {
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ //
+ // Adjust option string for date/time opcode.
+ //
+ ProcessStringForDateTime (MenuOption, OptionString, UpdateCol);
+ }
+
+ Width = (UINT16)gOptionBlockWidth - 1;
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ OptionLineNum = 0;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if (((Temp2 == 0)) && (Row <= BottomRow)) {
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ //
+ // For date/time question, it has three menu options for this qustion.
+ // The first/second menu options with the skip value is 0. the last one
+ // with skip value is 1.
+ //
+ if (MenuOption->Skip != 0) {
+ //
+ // For date/ time, print the last past (year for date and second for time)
+ // - 7 means skip [##/##/ for date and [##:##: for time.
+ //
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);
+ } else {
+ //
+ // For date/ time, print the first and second past (year for date and second for time)
+ // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
+ // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString) - 1, Highlight);
+ }
+ } else {
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
+ }
+
+ OptionLineNum++;
+ }
+
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&OptionString[Index]) != 0) {
+ if (Temp2 == 0) {
+ Row++;
+ //
+ // Since the Number of lines for this menu entry may or may not be reflected accurately
+ // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
+ // some testing to ensure we are keeping this in-sync.
+ //
+ // If the difference in rows is greater than or equal to the skip value, increase the skip value
+ //
+ if ((Row - MenuOption->Row) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp2 != 0) {
+ Temp2--;
+ }
+ }
+
+ Highlight = FALSE;
+
+ FreePool (OptionString);
+ }
+
+ //
+ // 2. Paint the description.
+ //
+ PromptWidth = GetWidth (MenuOption, &AdjustValue);
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ PromptLineNum = 0;
+
+ if ((MenuOption->Description == NULL) || (MenuOption->Description[0] == '\0')) {
+ PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);
+ PromptLineNum++;
+ } else {
+ for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp == 0) && (Row <= BottomRow)) {
+ //
+ // 1.Clean the start LEFT_SKIPPED_COLUMNS
+ //
+ PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_REF_OP) && (MenuOption->Col >= 2) && IsProcessingFirstRow) {
+ //
+ // Print Arrow for Goto button.
+ //
+ PrintCharAt (
+ MenuOption->Col - 2,
+ Row,
+ GEOMETRICSHAPE_RIGHT_TRIANGLE
+ );
+ IsProcessingFirstRow = FALSE;
+ }
+
+ DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);
+ PromptLineNum++;
+ }
+
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&MenuOption->Description[Index]) != 0) {
+ if (Temp == 0) {
+ Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp != 0) {
+ Temp--;
+ }
+ }
+
+ Highlight = FALSE;
+ }
+
+ //
+ // 3. If this is a text op with secondary text information
+ //
+ if ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT *)Statement->OpCode)->TextTwo != 0)) {
+ StringPtr = GetToken (((EFI_IFR_TEXT *)Statement->OpCode)->TextTwo, gFormData->HiiHandle);
+
+ Width = (UINT16)gOptionBlockWidth - 1;
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ OptionLineNum = 0;
+
+ for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp3 == 0) && (Row <= BottomRow)) {
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
+ OptionLineNum++;
+ }
+
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&StringPtr[Index]) != 0) {
+ if (Temp3 == 0) {
+ Row++;
+ //
+ // If the rows for text two is greater than or equal to the skip value, increase the skip value
+ //
+ if ((Row - MenuOption->Row) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp3 != 0) {
+ Temp3--;
+ }
+ }
+
+ FreePool (StringPtr);
+ }
+
+ //
+ // 4.Line number for Option string and prompt string are not equal.
+ // Clean the column whose line number is less.
+ //
+ if (HasOptionString (MenuOption) && (OptionLineNum != PromptLineNum)) {
+ Col = OptionLineNum < PromptLineNum ? MenuOption->OptCol : BeginCol;
+ Row = (OptionLineNum < PromptLineNum ? OptionLineNum : PromptLineNum) + MenuOption->Row;
+ Width = (UINT16)(OptionLineNum < PromptLineNum ? gOptionBlockWidth : PromptWidth + AdjustValue + SkipWidth);
+ MaxRow = (OptionLineNum < PromptLineNum ? PromptLineNum : OptionLineNum) + MenuOption->Row - 1;
+
+ while (Row <= MaxRow) {
+ DisplayMenuString (MenuOption, Col, Row++, L"", Width, FALSE);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Display menu and wait for user to select one menu option, then return it.
+ If AutoBoot is enabled, then if user doesn't select any option,
+ after period of time, it will automatically return the first menu option.
+
+ @param FormData The current form data info.
+
+ @retval EFI_SUCESSS Process the user selection success.
+ @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
+
+**/
+EFI_STATUS
+UiDisplayMenu (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINTN SkipValue;
+ INTN Difference;
+ UINTN DistanceValue;
+ UINTN Row;
+ UINTN Col;
+ UINTN Temp;
+ UINTN Temp2;
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ CHAR16 *StringRightPtr;
+ CHAR16 *StringErrorPtr;
+ CHAR16 *OptionString;
+ CHAR16 *HelpString;
+ CHAR16 *HelpHeaderString;
+ CHAR16 *HelpBottomString;
+ BOOLEAN NewLine;
+ BOOLEAN Repaint;
+ BOOLEAN UpArrow;
+ BOOLEAN DownArrow;
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NewPos;
+ LIST_ENTRY *TopOfScreen;
+ LIST_ENTRY *SavedListEntry;
+ UI_MENU_OPTION *MenuOption;
+ UI_MENU_OPTION *NextMenuOption;
+ UI_MENU_OPTION *SavedMenuOption;
+ UI_CONTROL_FLAG ControlFlag;
+ UI_SCREEN_OPERATION ScreenOperation;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ BROWSER_HOT_KEY *HotKey;
+ UINTN HelpPageIndex;
+ UINTN HelpPageCount;
+ UINTN RowCount;
+ UINTN HelpLine;
+ UINTN HelpHeaderLine;
+ UINTN HelpBottomLine;
+ BOOLEAN MultiHelpPage;
+ UINT16 EachLineWidth;
+ UINT16 HeaderLineWidth;
+ UINT16 BottomLineWidth;
+ EFI_STRING_ID HelpInfo;
+ UI_EVENT_TYPE EventType;
+ BOOLEAN SkipHighLight;
+ EFI_HII_VALUE *StatementValue;
+
+ EventType = UIEventNone;
+ Status = EFI_SUCCESS;
+ HelpString = NULL;
+ HelpHeaderString = NULL;
+ HelpBottomString = NULL;
+ OptionString = NULL;
+ ScreenOperation = UiNoOperation;
+ NewLine = TRUE;
+ HelpPageCount = 0;
+ HelpLine = 0;
+ RowCount = 0;
+ HelpBottomLine = 0;
+ HelpHeaderLine = 0;
+ HelpPageIndex = 0;
+ MultiHelpPage = FALSE;
+ EachLineWidth = 0;
+ HeaderLineWidth = 0;
+ BottomLineWidth = 0;
+ UpArrow = FALSE;
+ DownArrow = FALSE;
+ SkipValue = 0;
+ SkipHighLight = FALSE;
+
+ NextMenuOption = NULL;
+ SavedMenuOption = NULL;
+ HotKey = NULL;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ gModalSkipColumn = (CHAR16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;
+
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;
+
+ Row = TopRow;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;
+ } else {
+ Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;
+ }
+
+ FindTopMenu (FormData, &TopOfScreen, &NewPos, &SkipValue);
+ if (!IsListEmpty (&gMenuOption)) {
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ gUserInput->SelectedStatement = NextMenuOption->ThisTag;
+ }
+
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ ControlFlag = CfInitialization;
+ while (TRUE) {
+ switch (ControlFlag) {
+ case CfInitialization:
+ if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) ||
+ (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid)))
+ {
+ //
+ // Clear Statement range if different formset is painted.
+ //
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ gStatementDimensions.RightColumn,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ GetFieldTextColor ()
+ );
+ }
+
+ ControlFlag = CfRepaint;
+ break;
+
+ case CfRepaint:
+ ControlFlag = CfRefreshHighLight;
+
+ if (Repaint) {
+ //
+ // Display menu
+ //
+ DownArrow = FALSE;
+ UpArrow = FALSE;
+ Row = TopRow;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+
+ //
+ // 1. Check whether need to print the arrow up.
+ //
+ if (!ValueIsScroll (TRUE, TopOfScreen)) {
+ UpArrow = TRUE;
+ }
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
+ }
+
+ if (UpArrow) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
+ PrintCharAt (
+ gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ ARROW_UP
+ );
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+
+ //
+ // 2.Paint the menu.
+ //
+ for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {
+ MenuOption = MENU_OPTION_FROM_LINK (Link);
+ MenuOption->Row = Row;
+ MenuOption->Col = Col;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth + gModalSkipColumn;
+ } else {
+ MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;
+ }
+
+ if (MenuOption->NestInStatement) {
+ MenuOption->Col += SUBTITLE_INDENT;
+ }
+
+ //
+ // Save the highlight menu, will be used in CfRefreshHighLight case.
+ //
+ if (Link == NewPos) {
+ SavedMenuOption = MenuOption;
+ SkipHighLight = TRUE;
+ }
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ Status = DisplayOneMenu (
+ MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn + gModalSkipColumn,
+ Link == TopOfScreen ? SkipValue : 0,
+ BottomRow,
+ (BOOLEAN)((Link == NewPos) && IsSelectable (MenuOption)),
+ TRUE
+ );
+ } else {
+ Status = DisplayOneMenu (
+ MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Link == TopOfScreen ? SkipValue : 0,
+ BottomRow,
+ (BOOLEAN)((Link == NewPos) && IsSelectable (MenuOption)),
+ TRUE
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (gMisMatch) {
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+ }
+
+ //
+ // 3. Update the row info which will be used by next menu.
+ //
+ if (Link == TopOfScreen) {
+ Row += MenuOption->Skip - SkipValue;
+ } else {
+ Row += MenuOption->Skip;
+ }
+
+ if (Row > BottomRow) {
+ if (!ValueIsScroll (FALSE, Link)) {
+ DownArrow = TRUE;
+ }
+
+ Row = BottomRow + 1;
+ break;
+ }
+ }
+
+ //
+ // 3. Menus in this form may not cover all form, clean the remain field.
+ //
+ while (Row <= BottomRow) {
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);
+ }
+ }
+
+ //
+ // 4. Print the down arrow row.
+ //
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * +gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth (gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
+ }
+
+ if (DownArrow) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
+ PrintCharAt (
+ gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ ARROW_DOWN
+ );
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+
+ MenuOption = NULL;
+ }
+
+ break;
+
+ case CfRefreshHighLight:
+
+ //
+ // MenuOption: Last menu option that need to remove hilight
+ // MenuOption is set to NULL in Repaint
+ // NewPos: Current menu option that need to hilight
+ //
+ ControlFlag = CfUpdateHelpString;
+
+ ASSERT (NewPos != NULL);
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+
+ if (SkipHighLight) {
+ SkipHighLight = FALSE;
+ MenuOption = SavedMenuOption;
+ RefreshKeyHelp (gFormData, SavedMenuOption->ThisTag, FALSE);
+ break;
+ }
+
+ if (IsListEmpty (&gMenuOption)) {
+ //
+ // No menu option, just update the hotkey filed.
+ //
+ RefreshKeyHelp (gFormData, NULL, FALSE);
+ break;
+ }
+
+ if ((MenuOption != NULL) && (TopOfScreen == &MenuOption->Link)) {
+ Temp = SkipValue;
+ } else {
+ Temp = 0;
+ }
+
+ if (NewPos == TopOfScreen) {
+ Temp2 = SkipValue;
+ } else {
+ Temp2 = 0;
+ }
+
+ if ((MenuOption == NULL) || (NewPos != &MenuOption->Link)) {
+ if (MenuOption != NULL) {
+ //
+ // Remove the old highlight menu.
+ //
+ Status = DisplayOneMenu (
+ MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Temp,
+ BottomRow,
+ FALSE,
+ FALSE
+ );
+ }
+
+ //
+ // This is the current selected statement
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ RefreshKeyHelp (gFormData, MenuOption->ThisTag, FALSE);
+
+ if (!IsSelectable (MenuOption)) {
+ break;
+ }
+
+ Status = DisplayOneMenu (
+ MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Temp2,
+ BottomRow,
+ TRUE,
+ FALSE
+ );
+ }
+
+ break;
+
+ case CfUpdateHelpString:
+ ControlFlag = CfPrepareToReadKey;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ break;
+ }
+
+ //
+ // NewLine means only update highlight menu (remove old highlight and highlith
+ // the new one), not need to full repain the form.
+ //
+ if (Repaint || NewLine) {
+ if (IsListEmpty (&gMenuOption)) {
+ //
+ // Don't print anything if no mwnu option.
+ //
+ StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ } else {
+ //
+ // Don't print anything if it is a NULL help token
+ //
+ ASSERT (MenuOption != NULL);
+ HelpInfo = ((EFI_IFR_STATEMENT_HEADER *)((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;
+ Statement = MenuOption->ThisTag;
+ StatementValue = &Statement->CurrentValue;
+ if ((HelpInfo == 0) || !IsSelectable (MenuOption)) {
+ if (((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) && (StatementValue->Value.date.Month == 0xff)) || ((Statement->OpCode->OpCode == EFI_IFR_TIME_OP) && (StatementValue->Value.time.Hour == 0xff))) {
+ StringPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
+ } else {
+ StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ }
+ } else {
+ if (((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) && (StatementValue->Value.date.Month == 0xff)) || ((Statement->OpCode->OpCode == EFI_IFR_TIME_OP) && (StatementValue->Value.time.Hour == 0xff))) {
+ StringRightPtr = GetToken (HelpInfo, gFormData->HiiHandle);
+ StringErrorPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
+ StringPtr = AllocateZeroPool ((StrLen (StringRightPtr) + StrLen (StringErrorPtr)+ 1) * sizeof (CHAR16));
+ StrCpyS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringRightPtr);
+ StrCatS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringErrorPtr);
+ FreePool (StringRightPtr);
+ FreePool (StringErrorPtr);
+ } else {
+ StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);
+ }
+ }
+ }
+
+ RowCount = BottomRow - TopRow + 1;
+ HelpPageIndex = 0;
+ //
+ // 1.Calculate how many line the help string need to print.
+ //
+ if (HelpString != NULL) {
+ FreePool (HelpString);
+ HelpString = NULL;
+ }
+
+ HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);
+ FreePool (StringPtr);
+
+ if (HelpLine > RowCount) {
+ MultiHelpPage = TRUE;
+ StringPtr = GetToken (STRING_TOKEN (ADJUST_HELP_PAGE_UP), gHiiHandle);
+ if (HelpHeaderString != NULL) {
+ FreePool (HelpHeaderString);
+ HelpHeaderString = NULL;
+ }
+
+ HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0);
+ FreePool (StringPtr);
+ StringPtr = GetToken (STRING_TOKEN (ADJUST_HELP_PAGE_DOWN), gHiiHandle);
+ if (HelpBottomString != NULL) {
+ FreePool (HelpBottomString);
+ HelpBottomString = NULL;
+ }
+
+ HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);
+ FreePool (StringPtr);
+ //
+ // Calculate the help page count.
+ //
+ if (HelpLine > 2 * RowCount - 2) {
+ HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;
+ if ((HelpLine - RowCount + 1) % (RowCount - 2) != 0) {
+ HelpPageCount += 1;
+ }
+ } else {
+ HelpPageCount = 2;
+ }
+ } else {
+ MultiHelpPage = FALSE;
+ }
+ }
+
+ //
+ // Check whether need to show the 'More(U/u)' at the begin.
+ // Base on current direct info, here shows aligned to the right side of the column.
+ // If the direction is multi line and aligned to right side may have problem, so
+ // add ASSERT code here.
+ //
+ if (HelpPageIndex > 0) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
+ for (Index = 0; Index < HelpHeaderLine; Index++) {
+ ASSERT (HelpHeaderLine == 1);
+ ASSERT (GetStringWidth (HelpHeaderString) / 2 < ((UINT32)gHelpBlockWidth - 1));
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ PrintStringAt (
+ gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,
+ Index + TopRow,
+ &HelpHeaderString[Index * HeaderLineWidth]
+ );
+ }
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());
+ //
+ // Print the help string info.
+ //
+ if (!MultiHelpPage) {
+ for (Index = 0; Index < HelpLine; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ &HelpString[Index * EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+
+ for ( ; Index < RowCount; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
+ } else {
+ if (HelpPageIndex == 0) {
+ for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ &HelpString[Index * EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+ } else {
+ for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) &&
+ (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++)
+ {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow + HelpHeaderLine,
+ &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+
+ if (HelpPageIndex == HelpPageCount - 1) {
+ for ( ; Index < RowCount - HelpHeaderLine; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow + HelpHeaderLine,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
+ }
+ }
+ }
+
+ //
+ // Check whether need to print the 'More(D/d)' at the bottom.
+ // Base on current direct info, here shows aligned to the right side of the column.
+ // If the direction is multi line and aligned to right side may have problem, so
+ // add ASSERT code here.
+ //
+ if ((HelpPageIndex < HelpPageCount - 1) && MultiHelpPage) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
+ for (Index = 0; Index < HelpBottomLine; Index++) {
+ ASSERT (HelpBottomLine == 1);
+ ASSERT (GetStringWidth (HelpBottomString) / 2 < ((UINT32)gHelpBlockWidth - 1));
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ BottomRow + Index - HelpBottomLine + 1,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ PrintStringAt (
+ gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,
+ BottomRow + Index - HelpBottomLine + 1,
+ &HelpBottomString[Index * BottomLineWidth]
+ );
+ }
+ }
+
+ //
+ // Reset this flag every time we finish using it.
+ //
+ Repaint = FALSE;
+ NewLine = FALSE;
+ break;
+
+ case CfPrepareToReadKey:
+ ControlFlag = CfReadKey;
+ ScreenOperation = UiNoOperation;
+ break;
+
+ case CfReadKey:
+ ControlFlag = CfScreenOperation;
+
+ //
+ // Wait for user's selection
+ //
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status)) {
+ EventType = UIEventKey;
+ break;
+ }
+
+ //
+ // If we encounter error, continue to read another key in.
+ //
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ EventType = UiWaitForEvent (gST->ConIn->WaitForKey);
+ if (EventType == UIEventKey) {
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ }
+
+ break;
+ }
+
+ if (EventType == UIEventDriver) {
+ gMisMatch = TRUE;
+ gUserInput->Action = BROWSER_ACTION_NONE;
+ ControlFlag = CfExit;
+ break;
+ }
+
+ if (EventType == UIEventTimeOut) {
+ gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
+ ControlFlag = CfExit;
+ break;
+ }
+
+ switch (Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ if ((MenuOption == NULL) || MenuOption->GrayOut || MenuOption->ReadOnly) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ScreenOperation = UiSelect;
+ gDirection = 0;
+ break;
+
+ //
+ // We will push the adjustment of these numeric values directly to the input handler
+ // NOTE: we won't handle manual input numeric
+ //
+ case '+':
+ case '-':
+ //
+ // If the screen has no menu items, and the user didn't select UiReset
+ // ignore the selection and go back to reading keys.
+ //
+ ASSERT (MenuOption != NULL);
+ if (IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ Statement = MenuOption->ThisTag;
+ if ( (Statement->OpCode->OpCode == EFI_IFR_DATE_OP)
+ || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)
+ || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum (Statement->OpCode) != 0))
+ )
+ {
+ if (Key.UnicodeChar == '+') {
+ gDirection = SCAN_RIGHT;
+ } else {
+ gDirection = SCAN_LEFT;
+ }
+
+ Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
+ if (OptionString != NULL) {
+ FreePool (OptionString);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Repaint to clear possible error prompt pop-up
+ //
+ Repaint = TRUE;
+ NewLine = TRUE;
+ } else {
+ ControlFlag = CfExit;
+ }
+ }
+
+ break;
+
+ case '^':
+ ScreenOperation = UiUp;
+ break;
+
+ case 'V':
+ case 'v':
+ ScreenOperation = UiDown;
+ break;
+
+ case ' ':
+ if (IsListEmpty (&gMenuOption)) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ASSERT (MenuOption != NULL);
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP) && !MenuOption->GrayOut && !MenuOption->ReadOnly) {
+ ScreenOperation = UiSelect;
+ }
+
+ break;
+
+ case 'D':
+ case 'd':
+ if (!MultiHelpPage) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ControlFlag = CfUpdateHelpString;
+ HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;
+ break;
+
+ case 'U':
+ case 'u':
+ if (!MultiHelpPage) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ControlFlag = CfUpdateHelpString;
+ HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;
+ break;
+
+ case CHAR_NULL:
+ for (Index = 0; Index < mScanCodeNumber; Index++) {
+ if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
+ ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
+ break;
+ }
+ }
+
+ if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && ((Key.ScanCode == SCAN_ESC) || (Index == mScanCodeNumber))) {
+ //
+ // ModalForm has no ESC key and Hot Key.
+ //
+ ControlFlag = CfReadKey;
+ } else if (Index == mScanCodeNumber) {
+ //
+ // Check whether Key matches the registered hot key.
+ //
+ HotKey = NULL;
+ HotKey = GetHotKeyFromRegisterList (&Key);
+ if (HotKey != NULL) {
+ ScreenOperation = UiHotKey;
+ }
+ }
+
+ break;
+ }
+
+ break;
+
+ case CfScreenOperation:
+ if ((ScreenOperation != UiReset) && (ScreenOperation != UiHotKey)) {
+ //
+ // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
+ // ignore the selection and go back to reading keys.
+ //
+ if (IsListEmpty (&gMenuOption)) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+ }
+
+ for (Index = 0;
+ Index < ARRAY_SIZE (gScreenOperationToControlFlag);
+ Index++
+ )
+ {
+ if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
+ ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
+ break;
+ }
+ }
+
+ break;
+
+ case CfUiSelect:
+ ControlFlag = CfRepaint;
+
+ ASSERT (MenuOption != NULL);
+ Statement = MenuOption->ThisTag;
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ break;
+ }
+
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_REF_OP:
+ case EFI_IFR_ACTION_OP:
+ case EFI_IFR_RESET_BUTTON_OP:
+ ControlFlag = CfExit;
+ break;
+
+ default:
+ //
+ // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
+ //
+ RefreshKeyHelp (gFormData, Statement, TRUE);
+ Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
+
+ if (OptionString != NULL) {
+ FreePool (OptionString);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ RefreshKeyHelp (gFormData, Statement, FALSE);
+ break;
+ } else {
+ ControlFlag = CfExit;
+ break;
+ }
+ }
+
+ break;
+
+ case CfUiReset:
+ //
+ // We come here when someone press ESC
+ // If the policy is not exit front page when user press ESC, process here.
+ //
+ if (!FormExitPolicy ()) {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ ControlFlag = CfRepaint;
+ break;
+ }
+
+ gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
+ ControlFlag = CfExit;
+ break;
+
+ case CfUiHotKey:
+ ControlFlag = CfRepaint;
+
+ ASSERT (HotKey != NULL);
+
+ if (FxConfirmPopup (HotKey->Action)) {
+ gUserInput->Action = HotKey->Action;
+ if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ gUserInput->DefaultId = HotKey->DefaultId;
+ }
+
+ ControlFlag = CfExit;
+ } else {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ ControlFlag = CfRepaint;
+ }
+
+ break;
+
+ case CfUiLeft:
+ ControlFlag = CfRepaint;
+ ASSERT (MenuOption != NULL);
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ if (MenuOption->Sequence != 0) {
+ //
+ // In the middle or tail of the Date/Time op-code set, go left.
+ //
+ ASSERT (NewPos != NULL);
+ NewPos = NewPos->BackLink;
+ }
+ }
+
+ break;
+
+ case CfUiRight:
+ ControlFlag = CfRepaint;
+ ASSERT (MenuOption != NULL);
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ if (MenuOption->Sequence != 2) {
+ //
+ // In the middle or tail of the Date/Time op-code set, go left.
+ //
+ ASSERT (NewPos != NULL);
+ NewPos = NewPos->ForwardLink;
+ }
+ }
+
+ break;
+
+ case CfUiUp:
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+
+ SavedListEntry = NewPos;
+ ASSERT (NewPos != NULL);
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ ASSERT (MenuOption != NULL);
+
+ //
+ // Adjust Date/Time position before we advance forward.
+ //
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ NewPos = NewPos->BackLink;
+ //
+ // Find next selectable menu or the first menu beyond current form.
+ //
+ Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow, FALSE);
+ if (Difference < 0) {
+ //
+ // We hit the begining MenuOption that can be focused
+ // so we simply scroll to the top.
+ //
+ Repaint = TRUE;
+ if ((TopOfScreen != gMenuOption.ForwardLink) || (SkipValue != 0)) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ NewPos = SavedListEntry;
+ SkipValue = 0;
+ } else {
+ //
+ // Scroll up to the last page when we have arrived at top page.
+ //
+ TopOfScreen = FindTopOfScreenMenu (gMenuOption.BackLink, BottomRow - TopRow, &SkipValue);
+ NewPos = gMenuOption.BackLink;
+ MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow, TRUE);
+ }
+ } else {
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (MenuOption->Row < TopRow + Difference + NextMenuOption->Skip) {
+ //
+ // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
+ //
+ TopOfScreen = NewPos;
+ Repaint = TRUE;
+ SkipValue = 0;
+ }
+
+ //
+ // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
+ //
+ // BottomRow - TopRow + 1 means the total rows current forms supported.
+ // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
+ // and new top menu. New top menu will all shows in next form, but last highlight menu
+ // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
+ // last highlight menu.
+ //
+ if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) &&
+ (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1))
+ {
+ NewPos = SavedListEntry;
+ }
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiPageUp:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+ Repaint = TRUE;
+
+ Link = TopOfScreen;
+ //
+ // First minus the menu of the top screen, it's value is SkipValue.
+ //
+ if (SkipValue >= BottomRow - TopRow + 1) {
+ //
+ // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
+ // form of options to be show, so just update the SkipValue to show the next
+ // parts of options.
+ //
+ SkipValue -= BottomRow - TopRow + 1;
+ NewPos = TopOfScreen;
+ break;
+ } else {
+ Index = (BottomRow + 1) - SkipValue - TopRow;
+ }
+
+ TopOfScreen = FindTopOfScreenMenu (TopOfScreen, Index, &SkipValue);
+ NewPos = TopOfScreen;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, FALSE);
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ // Don't do this when we are already in the first page.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiPageDown:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+ Repaint = TRUE;
+
+ Link = TopOfScreen;
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);
+ Index = TopRow + NextMenuOption->Skip - SkipValue;
+ //
+ // Count to the menu option which will show at the top of the next form.
+ //
+ while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {
+ Link = Link->ForwardLink;
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);
+ Index = Index + NextMenuOption->Skip;
+ }
+
+ if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {
+ //
+ // Highlight on the last menu which can be highlight.
+ //
+ Repaint = FALSE;
+ MoveToNextStatement (TRUE, &Link, Index - TopRow, TRUE);
+ } else {
+ //
+ // Calculate the skip line for top of screen menu.
+ //
+ if (Link == TopOfScreen) {
+ //
+ // The top of screen menu option occupies the entire form.
+ //
+ SkipValue += BottomRow - TopRow + 1;
+ } else {
+ SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));
+ }
+
+ TopOfScreen = Link;
+ MenuOption = NULL;
+ //
+ // Move to the Next selectable menu.
+ //
+ MoveToNextStatement (FALSE, &Link, BottomRow - TopRow, TRUE);
+ }
+
+ //
+ // Save the menu as the next highlight menu.
+ //
+ NewPos = Link;
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ // Don't do this when we are already in the last page.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiDown:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ // NewPos points to the menu which is highlighted now.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+
+ if (NewPos == TopOfScreen) {
+ Temp2 = SkipValue;
+ } else {
+ Temp2 = 0;
+ }
+
+ SavedListEntry = NewPos;
+ //
+ // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
+ // to be one that progresses to the next set of op-codes, we need to advance to the last
+ // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
+ // checking can be done. The only other logic we need to introduce is that if a Date/Time
+ // op-code is the last entry in the menu, we need to rewind back to the first op-code of
+ // the Date/Time op-code.
+ //
+ AdjustDateAndTimePosition (FALSE, &NewPos);
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ NewPos = NewPos->ForwardLink;
+ //
+ // Find the next selectable menu.
+ //
+ if (MenuOption->Row + MenuOption->Skip - Temp2 > BottomRow + 1) {
+ if ((gMenuOption.ForwardLink == NewPos) || (&gMenuOption == NewPos)) {
+ Difference = -1;
+ } else {
+ Difference = 0;
+ }
+ } else {
+ Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow + 1 - (MenuOption->Row + MenuOption->Skip - Temp2), FALSE);
+ }
+
+ if (Difference < 0) {
+ //
+ // Scroll to the first page.
+ //
+ if ((TopOfScreen != gMenuOption.ForwardLink) || (SkipValue != 0)) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ } else {
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ }
+
+ NewPos = gMenuOption.ForwardLink;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);
+
+ SkipValue = 0;
+ //
+ // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+ break;
+ }
+
+ //
+ // Get next selected menu info.
+ //
+ AdjustDateAndTimePosition (FALSE, &NewPos);
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ if (NextMenuOption->Row == 0) {
+ UpdateOptionSkipLines (NextMenuOption);
+ }
+
+ //
+ // Calculate new highlight menu end row.
+ //
+ Temp = (MenuOption->Row + MenuOption->Skip - Temp2) + Difference + NextMenuOption->Skip - 1;
+ if (Temp > BottomRow) {
+ //
+ // Get the top screen menu info.
+ //
+ AdjustDateAndTimePosition (FALSE, &TopOfScreen);
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+
+ //
+ // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
+ // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
+ //
+ if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {
+ //
+ // Skip the top op-code
+ //
+ TopOfScreen = TopOfScreen->ForwardLink;
+ DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);
+
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+
+ //
+ // If we have a remainder, skip that many more op-codes until we drain the remainder
+ // Special case is the selected highlight menu has more than one form of menus.
+ //
+ while (DistanceValue >= SavedMenuOption->Skip && TopOfScreen != NewPos) {
+ //
+ // Since the Difference is greater than or equal to this op-code's skip value, skip it
+ //
+ DistanceValue = DistanceValue - (INTN)SavedMenuOption->Skip;
+ TopOfScreen = TopOfScreen->ForwardLink;
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+ }
+
+ //
+ // Since we will act on this op-code in the next routine, and increment the
+ // SkipValue, set the skips to one less than what is required.
+ //
+ if (TopOfScreen != NewPos) {
+ SkipValue = DistanceValue;
+ } else {
+ SkipValue = 0;
+ }
+ } else {
+ //
+ // Since we will act on this op-code in the next routine, and increment the
+ // SkipValue, set the skips to one less than what is required.
+ //
+ SkipValue += Temp - BottomRow;
+ }
+
+ Repaint = TRUE;
+ } else if (!IsSelectable (NextMenuOption)) {
+ //
+ // Continue to go down until scroll to next page or the selectable option is found.
+ //
+ ScreenOperation = UiDown;
+ ControlFlag = CfScreenOperation;
+ break;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+
+ //
+ // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
+ //
+ // BottomRow - TopRow + 1 means the total rows current forms supported.
+ // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
+ // and new top menu. New top menu will all shows in next form, but last highlight menu
+ // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
+ // last highlight menu.
+ //
+ if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) &&
+ (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1))
+ {
+ NewPos = SavedListEntry;
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo (NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiNoOperation:
+ ControlFlag = CfRepaint;
+ break;
+
+ case CfExit:
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ if (HelpString != NULL) {
+ FreePool (HelpString);
+ }
+
+ if (HelpHeaderString != NULL) {
+ FreePool (HelpHeaderString);
+ }
+
+ if (HelpBottomString != NULL) {
+ FreePool (HelpBottomString);
+ }
+
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ Free the UI Menu Option structure data.
+
+ @param MenuOptionList Point to the menu option list which need to be free.
+
+**/
+VOID
+FreeMenuOptionData (
+ LIST_ENTRY *MenuOptionList
+ )
+{
+ LIST_ENTRY *Link;
+ UI_MENU_OPTION *Option;
+
+ //
+ // Free menu option list
+ //
+ while (!IsListEmpty (MenuOptionList)) {
+ Link = GetFirstNode (MenuOptionList);
+ Option = MENU_OPTION_FROM_LINK (Link);
+ if (Option->Description != NULL) {
+ FreePool (Option->Description);
+ }
+
+ RemoveEntryList (&Option->Link);
+ FreePool (Option);
+ }
+}
+
+/**
+
+ Base on the browser status info to show an pop up message.
+
+**/
+VOID
+BrowserStatusProcess (
+ VOID
+ )
+{
+ CHAR16 *ErrorInfo;
+ EFI_INPUT_KEY Key;
+ EFI_EVENT WaitList[2];
+ EFI_EVENT RefreshIntervalEvent;
+ EFI_EVENT TimeOutEvent;
+ UINT8 TimeOut;
+ EFI_STATUS Status;
+ UINTN Index;
+ WARNING_IF_CONTEXT EventContext;
+ EFI_IFR_OP_HEADER *OpCodeBuf;
+ EFI_STRING_ID StringToken;
+ CHAR16 DiscardChange;
+ CHAR16 JumpToFormSet;
+ CHAR16 *PrintString;
+
+ if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
+ return;
+ }
+
+ StringToken = 0;
+ TimeOutEvent = NULL;
+ RefreshIntervalEvent = NULL;
+ OpCodeBuf = NULL;
+ if (gFormData->HighLightedStatement != NULL) {
+ OpCodeBuf = gFormData->HighLightedStatement->OpCode;
+ }
+
+ if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {
+ ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);
+
+ TimeOut = ((EFI_IFR_WARNING_IF *)OpCodeBuf)->TimeOut;
+ StringToken = ((EFI_IFR_WARNING_IF *)OpCodeBuf)->Warning;
+ } else {
+ TimeOut = 0;
+ if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&
+ ((OpCodeBuf != NULL) && (OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)))
+ {
+ StringToken = ((EFI_IFR_NO_SUBMIT_IF *)OpCodeBuf)->Error;
+ } else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&
+ ((OpCodeBuf != NULL) && (OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)))
+ {
+ StringToken = ((EFI_IFR_INCONSISTENT_IF *)OpCodeBuf)->Error;
+ }
+ }
+
+ if (StringToken != 0) {
+ ErrorInfo = GetToken (StringToken, gFormData->HiiHandle);
+ } else if (gFormData->ErrorString != NULL) {
+ //
+ // Only used to compatible with old setup browser.
+ // Not use this field in new browser core.
+ //
+ ErrorInfo = gFormData->ErrorString;
+ } else {
+ switch (gFormData->BrowserStatus) {
+ case BROWSER_SUBMIT_FAIL:
+ ErrorInfo = gSaveFailed;
+ break;
+
+ case BROWSER_FORM_NOT_FOUND:
+ ErrorInfo = gFormNotFound;
+ break;
+
+ case BROWSER_FORM_SUPPRESS:
+ ErrorInfo = gFormSuppress;
+ break;
+
+ case BROWSER_PROTOCOL_NOT_FOUND:
+ ErrorInfo = gProtocolNotFound;
+ break;
+
+ case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
+ ErrorInfo = gNoSubmitIfFailed;
+ break;
+
+ case BROWSER_RECONNECT_FAIL:
+ ErrorInfo = gReconnectFail;
+ break;
+
+ case BROWSER_RECONNECT_SAVE_CHANGES:
+ ErrorInfo = gReconnectConfirmChanges;
+ break;
+
+ case BROWSER_RECONNECT_REQUIRED:
+ ErrorInfo = gReconnectRequired;
+ break;
+
+ default:
+ ErrorInfo = gBrowserError;
+ break;
+ }
+ }
+
+ switch (gFormData->BrowserStatus) {
+ case BROWSER_SUBMIT_FAIL:
+ case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
+ case BROWSER_RECONNECT_SAVE_CHANGES:
+ ASSERT (gUserInput != NULL);
+ if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) {
+ PrintString = gSaveProcess;
+ JumpToFormSet = gJumpToFormSet[0];
+ DiscardChange = gDiscardChange[0];
+ } else if (gFormData->BrowserStatus == (BROWSER_RECONNECT_SAVE_CHANGES)) {
+ PrintString = gChangesOpt;
+ JumpToFormSet = gConfirmOptYes[0];
+ DiscardChange = gConfirmOptNo[0];
+ } else {
+ PrintString = gSaveNoSubmitProcess;
+ JumpToFormSet = gCheckError[0];
+ DiscardChange = gDiscardChange[0];
+ }
+
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL);
+ } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET)));
+
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) {
+ gUserInput->Action = BROWSER_ACTION_DISCARD;
+ } else {
+ gUserInput->Action = BROWSER_ACTION_GOTO;
+ }
+
+ break;
+
+ default:
+ if (TimeOut == 0) {
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ } else {
+ Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ EventContext.SyncEvent = TimeOutEvent;
+ EventContext.TimeOut = &TimeOut;
+ EventContext.ErrorInfo = ErrorInfo;
+
+ Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Show the dialog first to avoid long time not reaction.
+ //
+ gBS->SignalEvent (RefreshIntervalEvent);
+
+ Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND);
+ ASSERT_EFI_ERROR (Status);
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status) && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
+ break;
+ }
+
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ WaitList[0] = TimeOutEvent;
+ WaitList[1] = gST->ConIn->WaitForKey;
+
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Index == 0) {
+ //
+ // Timeout occur, close the hoot time out event.
+ //
+ break;
+ }
+ }
+
+ gBS->CloseEvent (TimeOutEvent);
+ gBS->CloseEvent (RefreshIntervalEvent);
+ }
+
+ break;
+ }
+
+ if (StringToken != 0) {
+ FreePool (ErrorInfo);
+ }
+}
+
+/**
+ Display one form, and return user input.
+
+ @param FormData Form Data to be shown.
+ @param UserInputData User input data.
+
+ @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
+ 2.Error info has show and return.
+ @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
+ @retval EFI_NOT_FOUND New form data has some error.
+**/
+EFI_STATUS
+EFIAPI
+FormDisplay (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FormData != NULL);
+ if (FormData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gUserInput = UserInputData;
+ gFormData = FormData;
+
+ //
+ // Process the status info first.
+ //
+ BrowserStatusProcess ();
+ if (gFormData->BrowserStatus != BROWSER_SUCCESS) {
+ //
+ // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = DisplayPageFrame (FormData, &gStatementDimensions);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Global Widths should be initialized before any MenuOption creation
+ // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
+ //
+ //
+ // Left right
+ // |<-.->|<-.........->|<- .........->|<-...........->|
+ // Skip Prompt Option Help
+ //
+ gOptionBlockWidth = (CHAR16)((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3) + 1;
+ gHelpBlockWidth = (CHAR16)(gOptionBlockWidth - 1 - LEFT_SKIPPED_COLUMNS);
+ gPromptBlockWidth = (CHAR16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gOptionBlockWidth - 1) - 1);
+
+ ConvertStatementToMenu ();
+
+ //
+ // Check whether layout is changed.
+ //
+ if ( mIsFirstForm
+ || (gOldFormEntry.HiiHandle != FormData->HiiHandle)
+ || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))
+ || (gOldFormEntry.FormId != FormData->FormId))
+ {
+ mStatementLayoutIsChanged = TRUE;
+ } else {
+ mStatementLayoutIsChanged = FALSE;
+ }
+
+ Status = UiDisplayMenu (FormData);
+
+ //
+ // Backup last form info.
+ //
+ mIsFirstForm = FALSE;
+ gOldFormEntry.HiiHandle = FormData->HiiHandle;
+ CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid);
+ gOldFormEntry.FormId = FormData->FormId;
+
+ //
+ // Free the Ui menu option list.
+ //
+ FreeMenuOptionData (&gMenuOption);
+
+ return Status;
+}
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+DriverClearDisplayPage (
+ VOID
+ )
+{
+ ClearDisplayPage ();
+ mIsFirstForm = TRUE;
+}
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+SetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ )
+{
+ CHAR16 *Ptr;
+
+ Ptr = Buffer;
+ while ((Size--) != 0) {
+ *(Ptr++) = Value;
+ }
+}
+
+/**
+ Initialize Setup Browser driver.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
+ @return Other value if failed to initialize the Setup Browser module.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDisplayEngine (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY HotKey;
+ EFI_STRING NewString;
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
+
+ //
+ // Publish our HII data
+ //
+ gHiiHandle = HiiAddPackages (
+ &gDisplayEngineGuid,
+ ImageHandle,
+ DisplayEngineStrings,
+ NULL
+ );
+ ASSERT (gHiiHandle != NULL);
+
+ //
+ // Install Form Display protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FromDisplayProt
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install HII Popup Protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEfiHiiPopupProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.HiiPopup
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeDisplayStrings ();
+
+ ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo));
+ ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry));
+
+ //
+ // Use BrowserEx2 protocol to register HotKey.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Register the default HotKey F9 and F10 again.
+ //
+ HotKey.UnicodeChar = CHAR_NULL;
+ HotKey.ScanCode = SCAN_F10;
+ NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);
+ FreePool (NewString);
+
+ HotKey.ScanCode = SCAN_F9;
+ NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);
+ FreePool (NewString);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the default unload handle for display core drivers.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+UnloadDisplayEngine (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ HiiRemovePackages (gHiiHandle);
+
+ FreeDisplayStrings ();
+
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+
+ return EFI_SUCCESS;
+}