diff options
Diffstat (limited to 'MdeModulePkg/Universal/DisplayEngineDxe')
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni | 32 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf | 124 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni | 28 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c | 8674 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h | 1476 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni | 268 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c | 3384 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/Popup.c | 1500 | ||||
| -rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c | 3234 |
9 files changed, 9360 insertions, 9360 deletions
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni index abf00de1dc..92e3317f64 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni +++ b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni @@ -1,16 +1,16 @@ -// /** @file
-// The DXE driver produces FORM DISPLAY ENGIEN protocol.
-//
-// A generic Timestamp driver producing Timestamp Protocol using UEFI APIs.
-//
-// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
-
-#string STR_MODULE_DESCRIPTION #language en-US "A generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
-
+// /** @file +// The DXE driver produces FORM DISPLAY ENGIEN protocol. +// +// A generic Timestamp driver producing Timestamp Protocol using UEFI APIs. +// +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Generic Timestamp driver producing Timestamp Protocol using UEFI APIs." + +#string STR_MODULE_DESCRIPTION #language en-US "A generic Timestamp driver producing Timestamp Protocol using UEFI APIs." + diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf index 07e19140b4..606a15aa10 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf +++ b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf @@ -1,62 +1,62 @@ -## @file
-# The DXE driver produces FORM DISPLAY ENGIEN protocol.
-#
-# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DisplayEngine
- MODULE_UNI_FILE = DisplayEngine.uni
- FILE_GUID = E660EA85-058E-4b55-A54B-F02F83A24707
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = InitializeDisplayEngine
- UNLOAD_IMAGE = UnloadDisplayEngine
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- FormDisplayStr.uni
- FormDisplay.c
- FormDisplay.h
- ProcessOptions.c
- InputHandler.c
- Popup.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- UefiDriverEntryPoint
- UefiBootServicesTableLib
- DebugLib
- BaseMemoryLib
- BaseLib
- PrintLib
- HiiLib
- MemoryAllocationLib
- CustomizedDisplayLib
-
-[Protocols]
- gEdkiiFormDisplayEngineProtocolGuid ## PRODUCES
- gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
- gEfiHiiPopupProtocolGuid ## PRODUCES
-
-[Depex]
- gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid
-
-[FeaturePcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES
-
-[UserExtensions.TianoCore."ExtraFiles"]
- DisplayEngineExtra.uni
+## @file +# The DXE driver produces FORM DISPLAY ENGIEN protocol. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DisplayEngine + MODULE_UNI_FILE = DisplayEngine.uni + FILE_GUID = E660EA85-058E-4b55-A54B-F02F83A24707 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeDisplayEngine + UNLOAD_IMAGE = UnloadDisplayEngine +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + FormDisplayStr.uni + FormDisplay.c + FormDisplay.h + ProcessOptions.c + InputHandler.c + Popup.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + BaseLib + PrintLib + HiiLib + MemoryAllocationLib + CustomizedDisplayLib + +[Protocols] + gEdkiiFormDisplayEngineProtocolGuid ## PRODUCES + gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES + gEfiHiiPopupProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + DisplayEngineExtra.uni diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni index a6cc8306b3..05e5e06e5d 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni +++ b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// DisplayEngine Localized Strings and Content
-//
-// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"DisplayEngine DXE Driver"
-
-
+// /** @file +// DisplayEngine Localized Strings and Content +// +// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"DisplayEngine DXE Driver" + + 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; +} diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h index 6e2670428e..3beed38e40 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h @@ -1,738 +1,738 @@ -/** @file
- FormDiplay protocol to show Form
-
-Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __FORM_DISPLAY_H__
-#define __FORM_DISPLAY_H__
-
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/BaseLib.h>
-#include <Library/HiiLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/PrintLib.h>
-#include <Library/CustomizedDisplayLib.h>
-
-#include <Protocol/FormBrowserEx2.h>
-#include <Protocol/SimpleTextIn.h>
-#include <Protocol/DisplayProtocol.h>
-#include <Protocol/HiiPopup.h>
-
-#include <Guid/MdeModuleHii.h>
-
-//
-// This is the generated header file which includes whatever needs to be exported (strings + IFR)
-//
-extern UINT8 DisplayEngineStrings[];
-extern EFI_SCREEN_DESCRIPTOR gStatementDimensions;
-extern USER_INPUT *gUserInput;
-extern FORM_DISPLAY_ENGINE_FORM *gFormData;
-extern EFI_HII_HANDLE gHiiHandle;
-extern UINT16 gDirection;
-extern LIST_ENTRY gMenuOption;
-extern CHAR16 *gConfirmOptYes;
-extern CHAR16 *gConfirmOptNo;
-extern CHAR16 *gConfirmOptOk;
-extern CHAR16 *gConfirmOptCancel;
-extern CHAR16 *gYesOption;
-extern CHAR16 *gNoOption;
-extern CHAR16 *gOkOption;
-extern CHAR16 *gCancelOption;
-extern CHAR16 *gErrorPopup;
-extern CHAR16 *gWarningPopup;
-extern CHAR16 *gInfoPopup;
-
-//
-// Browser Global Strings
-//
-extern CHAR16 *gSaveFailed;
-extern CHAR16 *gPromptForData;
-extern CHAR16 *gPromptForPassword;
-extern CHAR16 *gPromptForNewPassword;
-extern CHAR16 *gConfirmPassword;
-extern CHAR16 *gConfirmError;
-extern CHAR16 *gPassowordInvalid;
-extern CHAR16 *gPressEnter;
-extern CHAR16 *gEmptyString;
-extern CHAR16 *gMiniString;
-extern CHAR16 *gOptionMismatch;
-extern CHAR16 *gFormSuppress;
-extern CHAR16 *gProtocolNotFound;
-extern CHAR16 *gPasswordUnsupported;
-
-extern CHAR16 gPromptBlockWidth;
-extern CHAR16 gOptionBlockWidth;
-extern CHAR16 gHelpBlockWidth;
-extern CHAR16 *mUnknownString;
-extern BOOLEAN gMisMatch;
-
-//
-// Screen definitions
-//
-
-#define LEFT_SKIPPED_COLUMNS 3
-#define SCROLL_ARROW_HEIGHT 1
-#define POPUP_PAD_SPACE_COUNT 5
-#define POPUP_FRAME_WIDTH 2
-
-#define UPPER_LOWER_CASE_OFFSET 0x20
-
-//
-// Display definitions
-//
-#define LEFT_ONEOF_DELIMITER L'<'
-#define RIGHT_ONEOF_DELIMITER L'>'
-
-#define LEFT_NUMERIC_DELIMITER L'['
-#define RIGHT_NUMERIC_DELIMITER L']'
-
-#define LEFT_CHECKBOX_DELIMITER L'['
-#define RIGHT_CHECKBOX_DELIMITER L']'
-
-#define CHECK_ON L'X'
-#define CHECK_OFF L' '
-
-#define TIME_SEPARATOR L':'
-#define DATE_SEPARATOR L'/'
-
-#define SUBTITLE_INDENT 2
-
-//
-// This is the Input Error Message
-//
-#define INPUT_ERROR 1
-
-//
-// This is the NV RAM update required Message
-//
-#define NV_UPDATE_REQUIRED 2
-//
-// Time definitions
-//
-#define ONE_SECOND 10000000
-
-//
-// It take 23 characters including the NULL to print a 64 bits number with "[" and "]".
-// pow(2, 64) = [18446744073709551616]
-// with extra '-' flat, set the width to 24.
-//
-#define MAX_NUMERIC_INPUT_WIDTH 24
-
-#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
-#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
-#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
-#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
-#define EFI_HII_EXPRESSION_DISABLE_IF 4
-
-//
-// Character definitions
-//
-#define CHAR_SPACE 0x0020
-
-#define FORM_DISPLAY_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'D', 'D', 'V')
-typedef struct {
- UINT32 Signature;
-
- EFI_HANDLE Handle;
-
- //
- // Produced protocol
- //
- EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FromDisplayProt;
- EFI_HII_POPUP_PROTOCOL HiiPopup;
-} FORM_DISPLAY_DRIVER_PRIVATE_DATA;
-
-typedef enum {
- UiNoOperation,
- UiSelect,
- UiUp,
- UiDown,
- UiLeft,
- UiRight,
- UiReset,
- UiPrevious,
- UiPageUp,
- UiPageDown,
- UiHotKey,
- UiMaxOperation
-} UI_SCREEN_OPERATION;
-
-typedef enum {
- CfInitialization,
- CfCheckSelection,
- CfRepaint,
- CfRefreshHighLight,
- CfUpdateHelpString,
- CfPrepareToReadKey,
- CfReadKey,
- CfScreenOperation,
- CfUiSelect,
- CfUiReset,
- CfUiLeft,
- CfUiRight,
- CfUiUp,
- CfUiPageUp,
- CfUiPageDown,
- CfUiDown,
- CfUiNoOperation,
- CfExit,
- CfUiHotKey,
- CfMaxControlFlag
-} UI_CONTROL_FLAG;
-
-typedef enum {
- UIEventNone,
- UIEventKey,
- UIEventTimeOut,
- UIEventDriver
-} UI_EVENT_TYPE;
-
-typedef struct {
- UINT16 ScanCode;
- UI_SCREEN_OPERATION ScreenOperation;
-} SCAN_CODE_TO_SCREEN_OPERATION;
-
-typedef struct {
- UI_SCREEN_OPERATION ScreenOperation;
- UI_CONTROL_FLAG ControlFlag;
-} SCREEN_OPERATION_T0_CONTROL_FLAG;
-
-typedef struct {
- EFI_HII_HANDLE HiiHandle;
- UINT16 FormId;
-
- //
- // Info for the highlight question.
- // HLT means highlight
- //
- // If one statement has questionid, save questionid info to find the question.
- // If one statement not has questionid info, save the opcode info to find the
- // statement. If more than one statement has same opcode in one form(just like
- // empty subtitle info may has more than one info one form), also use Index
- // info to find the statement.
- //
- EFI_QUESTION_ID HLTQuestionId;
- EFI_IFR_OP_HEADER *HLTOpCode;
- UINTN HLTIndex;
- UINTN HLTSequence;
-
- //
- // Info for the top of screen question.
- // TOS means Top Of Screen
- //
- EFI_QUESTION_ID TOSQuestionId;
- EFI_IFR_OP_HEADER *TOSOpCode;
- UINTN TOSIndex;
-
- UINT16 SkipValue;
-} DISPLAY_HIGHLIGHT_MENU_INFO;
-
-typedef struct {
- EFI_EVENT SyncEvent;
- UINT8 *TimeOut;
- CHAR16 *ErrorInfo;
-} WARNING_IF_CONTEXT;
-
-#define UI_MENU_OPTION_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'm')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- EFI_HII_HANDLE Handle;
- FORM_DISPLAY_ENGINE_STATEMENT *ThisTag;
- UINT16 EntryNumber;
-
- UINTN Row;
- UINTN Col;
- UINTN OptCol;
- CHAR16 *Description;
- UINTN Skip; // Number of lines
-
- //
- // Display item sequence for date/time
- // Date: Month/Day/Year
- // Sequence: 0 1 2
- //
- // Time: Hour : Minute : Second
- // Sequence: 0 1 2
- //
- //
- UINTN Sequence;
-
- BOOLEAN GrayOut;
- BOOLEAN ReadOnly;
-
- //
- // Whether user could change value of this item
- //
- BOOLEAN IsQuestion;
- BOOLEAN NestInStatement;
-} UI_MENU_OPTION;
-
-#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE)
-
-#define USER_SELECTABLE_OPTION_OK_WIDTH StrLen (gOkOption)
-#define USER_SELECTABLE_OPTION_OK_CAL_WIDTH (StrLen (gOkOption) + StrLen (gCancelOption))
-#define USER_SELECTABLE_OPTION_YES_NO_WIDTH (StrLen (gYesOption) + StrLen (gNoOption))
-#define USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH (StrLen (gYesOption) + StrLen (gNoOption) + StrLen (gCancelOption))
-
-#define USER_SELECTABLE_OPTION_SKIP_WIDTH 2
-
-//
-// +-------------------------------------------+ // POPUP_BORDER }
-// | ERROR/WARNING/INFO | // POPUP_STYLE_STRING_HEIGHT } POPUP_HEADER_HEIGHT
-// |-------------------------------------------| // POPUP_EMPTY_LINE_HEIGHT }
-// | popup messages |
-// | | // POPUP_EMPTY_LINE_HEIGHT }
-// | user selectable options | // POPUP_USER_SELECTABLE_OPTION_HEIGHT } POPUP_FOOTER_HEIGHT
-// +-------------------------------------------+ // POPUP_BORDER }
-//
-#define POPUP_BORDER 1
-#define POPUP_EMPTY_LINE_HEIGHT 1
-#define POPUP_STYLE_STRING_HEIGHT 1
-#define POPUP_USER_SELECTABLE_OPTION_HEIGHT 1
-
-#define POPUP_HEADER_HEIGHT (POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT + POPUP_EMPTY_LINE_HEIGHT)
-#define POPUP_FOOTER_HEIGHT (POPUP_EMPTY_LINE_HEIGHT + POPUP_USER_SELECTABLE_OPTION_HEIGHT + POPUP_BORDER)
-
-#define USER_SELECTABLE_OPTION_SIGNATURE SIGNATURE_32 ('u', 's', 's', 'o')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- EFI_HII_POPUP_SELECTION OptionType;
- CHAR16 *OptionString;
- //
- // Display item sequence for user select options
- // Ok: Ok
- // Sequence: 0
- //
- // Ok/Cancel: Ok : Cancel
- // Sequence: 0 1
- //
- // Yes/No: Yes : No
- // Sequence: 0 1
- //
- // Yes/No/Cancel: Yes : No: Cancel
- // Sequence: 0 1 2
- //
- UINTN Sequence;
- UINTN OptionRow;
- UINTN OptionCol;
- UINTN MaxSequence;
- UINTN MinSequence;
-} USER_SELECTABLE_OPTION;
-
-#define SELECTABLE_OPTION_FROM_LINK(a) CR (a, USER_SELECTABLE_OPTION, Link, USER_SELECTABLE_OPTION_SIGNATURE)
-
-/**
- Print Question Value according to it's storage width and display attributes.
-
- @param Question The Question to be printed.
- @param FormattedNumber Buffer for output string.
- @param BufferSize The FormattedNumber buffer size in bytes.
-
- @retval EFI_SUCCESS Print success.
- @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
-
-**/
-EFI_STATUS
-PrintFormattedNumber (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
- IN OUT CHAR16 *FormattedNumber,
- IN UINTN BufferSize
- );
-
-/**
- Set value of a data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
- @param Value The value to be set.
-
-**/
-VOID
-SetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index,
- IN UINT64 Value
- );
-
-/**
- Return data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
-
- @retval Value The data to be returned
-
-**/
-UINT64
-GetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index
- );
-
-/**
- Search an Option of a Question by its value.
-
- @param Question The Question
- @param OptionValue Value for Option to be searched.
-
- @retval Pointer Pointer to the found Option.
- @retval NULL Option not found.
-
-**/
-DISPLAY_QUESTION_OPTION *
-ValueToOption (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
- IN EFI_HII_VALUE *OptionValue
- );
-
-/**
- Compare two Hii value.
-
- @param Value1 Expression value to compare on left-hand.
- @param Value2 Expression value to compare on right-hand.
- @param Result Return value after compare.
- retval 0 Two operators equal.
- return Positive value if Value1 is greater than Value2.
- retval Negative value if Value1 is less than Value2.
- @param HiiHandle Only required for string compare.
-
- @retval other Could not perform compare on two values.
- @retval EFI_SUCCESS Compare the value success.
-
-**/
-EFI_STATUS
-CompareHiiValue (
- IN EFI_HII_VALUE *Value1,
- IN EFI_HII_VALUE *Value2,
- OUT INTN *Result,
- IN EFI_HII_HANDLE HiiHandle OPTIONAL
- );
-
-/**
- Draw a pop up windows based on the dimension, number of lines and
- strings specified.
-
- @param RequestedWidth The width of the pop-up.
- @param NumberOfLines The number of lines.
- @param ... A series of text strings that displayed in the pop-up.
-
-**/
-VOID
-EFIAPI
-CreateMultiStringPopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- ...
- );
-
-/**
- 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
- );
-
-/**
- Get the string based on the StringId and HII Package List Handle.
-
- @param Token The String's ID.
- @param HiiHandle The Hii handle for this string package.
-
- @return The output string.
-
-**/
-CHAR16 *
-GetToken (
- IN EFI_STRING_ID Token,
- IN EFI_HII_HANDLE HiiHandle
- );
-
-/**
- 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
- );
-
-/**
- This routine reads a numeric value from the user input.
-
- @param MenuOption Pointer to the current input menu.
-
- @retval EFI_SUCCESS If numerical input is read successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-GetNumericInput (
- IN UI_MENU_OPTION *MenuOption
- );
-
-/**
- Get string or password input from user.
-
- @param MenuOption Pointer to the current input menu.
- @param Prompt The prompt string shown on popup window.
- @param StringPtr Old user input and destination for use input string.
-
- @retval EFI_SUCCESS If string input is read successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-ReadString (
- IN UI_MENU_OPTION *MenuOption,
- IN CHAR16 *Prompt,
- IN OUT CHAR16 *StringPtr
- );
-
-/**
- Draw a pop up windows based on the dimension, number of lines and
- strings specified.
-
- @param RequestedWidth The width of the pop-up.
- @param NumberOfLines The number of lines.
- @param Marker The variable argument list for the list of string to be printed.
-
-**/
-VOID
-CreateSharedPopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- IN VA_LIST Marker
- );
-
-/**
- Wait for a key to be pressed by user.
-
- @param Key The key which is pressed by user.
-
- @retval EFI_SUCCESS The function always completed successfully.
-
-**/
-EFI_STATUS
-WaitForKeyStroke (
- OUT EFI_INPUT_KEY *Key
- );
-
-/**
- Get selection for OneOf and OrderedList (Left/Right will be ignored).
-
- @param MenuOption Pointer to the current input menu.
-
- @retval EFI_SUCCESS If Option input is processed successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-GetSelectionInputPopUp (
- IN UI_MENU_OPTION *MenuOption
- );
-
-/**
- Process the help string: Split StringPtr to several lines of strings stored in
- FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
-
- @param StringPtr The entire help string.
- @param FormattedString The oupput formatted string.
- @param EachLineWidth The max string length of each line in the formatted string.
- @param RowCount TRUE: if Question is selected.
-
-**/
-UINTN
-ProcessHelpString (
- IN CHAR16 *StringPtr,
- OUT CHAR16 **FormattedString,
- OUT UINT16 *EachLineWidth,
- IN UINTN RowCount
- );
-
-/**
- Process a Question's Option (whether selected or un-selected).
-
- @param MenuOption The MenuOption for this Question.
- @param Selected TRUE: if Question is selected.
- @param OptionString Pointer of the Option String to be displayed.
- @param SkipErrorValue Whether need to return when value without option for it.
-
- @retval EFI_SUCCESS Question Option process success.
- @retval Other Question Option process fail.
-
-**/
-EFI_STATUS
-ProcessOptions (
- IN UI_MENU_OPTION *MenuOption,
- IN BOOLEAN Selected,
- OUT CHAR16 **OptionString,
- IN BOOLEAN SkipErrorValue
- );
-
-/**
- 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
- );
-
-/**
- Display one form, and return user input.
-
- @param FormData Form Data to be shown.
- @param UserInputData User input data.
-
- @retval EFI_SUCCESS Form Data is shown, and user input is got.
-**/
-EFI_STATUS
-EFIAPI
-FormDisplay (
- IN FORM_DISPLAY_ENGINE_FORM *FormData,
- OUT USER_INPUT *UserInputData
- );
-
-/**
- Clear Screen to the initial state.
-**/
-VOID
-EFIAPI
-DriverClearDisplayPage (
- VOID
- );
-
-/**
- Exit Display and Clear Screen to the original state.
-
-**/
-VOID
-EFIAPI
-ExitDisplay (
- VOID
- );
-
-/**
- Process nothing.
-
- @param Event The Event need to be process
- @param Context The context of the event.
-
-**/
-VOID
-EFIAPI
-EmptyEventProcess (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Process for the refresh interval statement.
-
- @param Event The Event need to be process
- @param Context The context of the event.
-
-**/
-VOID
-EFIAPI
-RefreshTimeOutProcess (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- 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
- );
-
-/**
- Displays a popup window.
-
- @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance.
- @param PopupStyle Popup style to use.
- @param PopupType Type of the popup to display.
- @param HiiHandle HII handle of the string pack containing Message
- @param Message A message to display in the popup box.
- @param UserSelection User selection.
-
- @retval EFI_SUCCESS The popup box was successfully displayed.
- @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string.
- @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box.
-
-**/
-EFI_STATUS
-EFIAPI
-CreatePopup (
- IN EFI_HII_POPUP_PROTOCOL *This,
- IN EFI_HII_POPUP_STYLE PopupStyle,
- IN EFI_HII_POPUP_TYPE PopupType,
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_STRING_ID Message,
- OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL
- );
-
-#endif
+/** @file + FormDiplay protocol to show Form + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FORM_DISPLAY_H__ +#define __FORM_DISPLAY_H__ + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/HiiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PrintLib.h> +#include <Library/CustomizedDisplayLib.h> + +#include <Protocol/FormBrowserEx2.h> +#include <Protocol/SimpleTextIn.h> +#include <Protocol/DisplayProtocol.h> +#include <Protocol/HiiPopup.h> + +#include <Guid/MdeModuleHii.h> + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// +extern UINT8 DisplayEngineStrings[]; +extern EFI_SCREEN_DESCRIPTOR gStatementDimensions; +extern USER_INPUT *gUserInput; +extern FORM_DISPLAY_ENGINE_FORM *gFormData; +extern EFI_HII_HANDLE gHiiHandle; +extern UINT16 gDirection; +extern LIST_ENTRY gMenuOption; +extern CHAR16 *gConfirmOptYes; +extern CHAR16 *gConfirmOptNo; +extern CHAR16 *gConfirmOptOk; +extern CHAR16 *gConfirmOptCancel; +extern CHAR16 *gYesOption; +extern CHAR16 *gNoOption; +extern CHAR16 *gOkOption; +extern CHAR16 *gCancelOption; +extern CHAR16 *gErrorPopup; +extern CHAR16 *gWarningPopup; +extern CHAR16 *gInfoPopup; + +// +// Browser Global Strings +// +extern CHAR16 *gSaveFailed; +extern CHAR16 *gPromptForData; +extern CHAR16 *gPromptForPassword; +extern CHAR16 *gPromptForNewPassword; +extern CHAR16 *gConfirmPassword; +extern CHAR16 *gConfirmError; +extern CHAR16 *gPassowordInvalid; +extern CHAR16 *gPressEnter; +extern CHAR16 *gEmptyString; +extern CHAR16 *gMiniString; +extern CHAR16 *gOptionMismatch; +extern CHAR16 *gFormSuppress; +extern CHAR16 *gProtocolNotFound; +extern CHAR16 *gPasswordUnsupported; + +extern CHAR16 gPromptBlockWidth; +extern CHAR16 gOptionBlockWidth; +extern CHAR16 gHelpBlockWidth; +extern CHAR16 *mUnknownString; +extern BOOLEAN gMisMatch; + +// +// Screen definitions +// + +#define LEFT_SKIPPED_COLUMNS 3 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// Display definitions +// +#define LEFT_ONEOF_DELIMITER L'<' +#define RIGHT_ONEOF_DELIMITER L'>' + +#define LEFT_NUMERIC_DELIMITER L'[' +#define RIGHT_NUMERIC_DELIMITER L']' + +#define LEFT_CHECKBOX_DELIMITER L'[' +#define RIGHT_CHECKBOX_DELIMITER L']' + +#define CHECK_ON L'X' +#define CHECK_OFF L' ' + +#define TIME_SEPARATOR L':' +#define DATE_SEPARATOR L'/' + +#define SUBTITLE_INDENT 2 + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// It take 23 characters including the NULL to print a 64 bits number with "[" and "]". +// pow(2, 64) = [18446744073709551616] +// with extra '-' flat, set the width to 24. +// +#define MAX_NUMERIC_INPUT_WIDTH 24 + +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 + +#define FORM_DISPLAY_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'D', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FromDisplayProt; + EFI_HII_POPUP_PROTOCOL HiiPopup; +} FORM_DISPLAY_DRIVER_PRIVATE_DATA; + +typedef enum { + UiNoOperation, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiPrevious, + UiPageUp, + UiPageDown, + UiHotKey, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiNoOperation, + CfExit, + CfUiHotKey, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +typedef enum { + UIEventNone, + UIEventKey, + UIEventTimeOut, + UIEventDriver +} UI_EVENT_TYPE; + +typedef struct { + UINT16 ScanCode; + UI_SCREEN_OPERATION ScreenOperation; +} SCAN_CODE_TO_SCREEN_OPERATION; + +typedef struct { + UI_SCREEN_OPERATION ScreenOperation; + UI_CONTROL_FLAG ControlFlag; +} SCREEN_OPERATION_T0_CONTROL_FLAG; + +typedef struct { + EFI_HII_HANDLE HiiHandle; + UINT16 FormId; + + // + // Info for the highlight question. + // HLT means highlight + // + // If one statement has questionid, save questionid info to find the question. + // If one statement not has questionid info, save the opcode info to find the + // statement. If more than one statement has same opcode in one form(just like + // empty subtitle info may has more than one info one form), also use Index + // info to find the statement. + // + EFI_QUESTION_ID HLTQuestionId; + EFI_IFR_OP_HEADER *HLTOpCode; + UINTN HLTIndex; + UINTN HLTSequence; + + // + // Info for the top of screen question. + // TOS means Top Of Screen + // + EFI_QUESTION_ID TOSQuestionId; + EFI_IFR_OP_HEADER *TOSOpCode; + UINTN TOSIndex; + + UINT16 SkipValue; +} DISPLAY_HIGHLIGHT_MENU_INFO; + +typedef struct { + EFI_EVENT SyncEvent; + UINT8 *TimeOut; + CHAR16 *ErrorInfo; +} WARNING_IF_CONTEXT; + +#define UI_MENU_OPTION_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'm') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE Handle; + FORM_DISPLAY_ENGINE_STATEMENT *ThisTag; + UINT16 EntryNumber; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; // Number of lines + + // + // Display item sequence for date/time + // Date: Month/Day/Year + // Sequence: 0 1 2 + // + // Time: Hour : Minute : Second + // Sequence: 0 1 2 + // + // + UINTN Sequence; + + BOOLEAN GrayOut; + BOOLEAN ReadOnly; + + // + // Whether user could change value of this item + // + BOOLEAN IsQuestion; + BOOLEAN NestInStatement; +} UI_MENU_OPTION; + +#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) + +#define USER_SELECTABLE_OPTION_OK_WIDTH StrLen (gOkOption) +#define USER_SELECTABLE_OPTION_OK_CAL_WIDTH (StrLen (gOkOption) + StrLen (gCancelOption)) +#define USER_SELECTABLE_OPTION_YES_NO_WIDTH (StrLen (gYesOption) + StrLen (gNoOption)) +#define USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH (StrLen (gYesOption) + StrLen (gNoOption) + StrLen (gCancelOption)) + +#define USER_SELECTABLE_OPTION_SKIP_WIDTH 2 + +// +// +-------------------------------------------+ // POPUP_BORDER } +// | ERROR/WARNING/INFO | // POPUP_STYLE_STRING_HEIGHT } POPUP_HEADER_HEIGHT +// |-------------------------------------------| // POPUP_EMPTY_LINE_HEIGHT } +// | popup messages | +// | | // POPUP_EMPTY_LINE_HEIGHT } +// | user selectable options | // POPUP_USER_SELECTABLE_OPTION_HEIGHT } POPUP_FOOTER_HEIGHT +// +-------------------------------------------+ // POPUP_BORDER } +// +#define POPUP_BORDER 1 +#define POPUP_EMPTY_LINE_HEIGHT 1 +#define POPUP_STYLE_STRING_HEIGHT 1 +#define POPUP_USER_SELECTABLE_OPTION_HEIGHT 1 + +#define POPUP_HEADER_HEIGHT (POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT + POPUP_EMPTY_LINE_HEIGHT) +#define POPUP_FOOTER_HEIGHT (POPUP_EMPTY_LINE_HEIGHT + POPUP_USER_SELECTABLE_OPTION_HEIGHT + POPUP_BORDER) + +#define USER_SELECTABLE_OPTION_SIGNATURE SIGNATURE_32 ('u', 's', 's', 'o') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + EFI_HII_POPUP_SELECTION OptionType; + CHAR16 *OptionString; + // + // Display item sequence for user select options + // Ok: Ok + // Sequence: 0 + // + // Ok/Cancel: Ok : Cancel + // Sequence: 0 1 + // + // Yes/No: Yes : No + // Sequence: 0 1 + // + // Yes/No/Cancel: Yes : No: Cancel + // Sequence: 0 1 2 + // + UINTN Sequence; + UINTN OptionRow; + UINTN OptionCol; + UINTN MaxSequence; + UINTN MinSequence; +} USER_SELECTABLE_OPTION; + +#define SELECTABLE_OPTION_FROM_LINK(a) CR (a, USER_SELECTABLE_OPTION, Link, USER_SELECTABLE_OPTION_SIGNATURE) + +/** + Print Question Value according to it's storage width and display attributes. + + @param Question The Question to be printed. + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ); + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ); + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ); + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +DISPLAY_QUESTION_OPTION * +ValueToOption ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ); + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ); + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +EFIAPI +CreateMultiStringPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + ... + ); + +/** + 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 + ); + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The Hii handle for this string package. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ); + +/** + 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 + ); + +/** + This routine reads a numeric value from the user input. + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_OPTION *MenuOption + ); + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Old user input and destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + IN OUT CHAR16 *StringPtr + ); + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param Marker The variable argument list for the list of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN VA_LIST Marker + ); + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ); + +/** + Get selection for OneOf and OrderedList (Left/Right will be ignored). + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_OPTION *MenuOption + ); + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param FormattedString The oupput formatted string. + @param EachLineWidth The max string length of each line in the formatted string. + @param RowCount TRUE: if Question is selected. + +**/ +UINTN +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + OUT UINT16 *EachLineWidth, + IN UINTN RowCount + ); + +/** + Process a Question's Option (whether selected or un-selected). + + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + @param SkipErrorValue Whether need to return when value without option for it. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString, + IN BOOLEAN SkipErrorValue + ); + +/** + 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 + ); + +/** + Display one form, and return user input. + + @param FormData Form Data to be shown. + @param UserInputData User input data. + + @retval EFI_SUCCESS Form Data is shown, and user input is got. +**/ +EFI_STATUS +EFIAPI +FormDisplay ( + IN FORM_DISPLAY_ENGINE_FORM *FormData, + OUT USER_INPUT *UserInputData + ); + +/** + Clear Screen to the initial state. +**/ +VOID +EFIAPI +DriverClearDisplayPage ( + VOID + ); + +/** + Exit Display and Clear Screen to the original state. + +**/ +VOID +EFIAPI +ExitDisplay ( + VOID + ); + +/** + Process nothing. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +EmptyEventProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Process for the refresh interval statement. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +RefreshTimeOutProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + 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 + ); + +/** + Displays a popup window. + + @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance. + @param PopupStyle Popup style to use. + @param PopupType Type of the popup to display. + @param HiiHandle HII handle of the string pack containing Message + @param Message A message to display in the popup box. + @param UserSelection User selection. + + @retval EFI_SUCCESS The popup box was successfully displayed. + @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string. + @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box. + +**/ +EFI_STATUS +EFIAPI +CreatePopup ( + IN EFI_HII_POPUP_PROTOCOL *This, + IN EFI_HII_POPUP_STYLE PopupStyle, + IN EFI_HII_POPUP_TYPE PopupType, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID Message, + OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL + ); + +#endif diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni index 5e3c35a2c6..a1078b73c0 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni @@ -1,134 +1,134 @@ -// *++
-//
-// Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// Module Name:
-//
-// SetupBrowserStr.uni
-//
-// Abstract:
-//
-// String definitions for Browser.
-//
-// --*/
-
-
-/=#
-
-#langdef en-US "English"
-#langdef fr-FR "Français"
-
-#string UNKNOWN_STRING #language en-US "!"
- #language fr-FR "!"
-#string STATUS_BROWSER_ERROR #language en-US "Browser met some error, return!"
- #language fr-FR "Browser met some error, return!"
-#string STATUS_BROWSER_FORM_NOT_FOUND #language en-US "Form not found, return!"
- #language fr-FR "Form not found, return!"
-#string STATUS_BROWSER_NO_SUBMIT_IF #language en-US "Not allowed to submit, return!"
- #language fr-FR "Not allowed to submit, return!"
-#string FUNCTION_NINE_STRING #language en-US "F9=Reset to Defaults"
- #language fr-FR "F9=Reset à Défauts"
-#string FUNCTION_TEN_STRING #language en-US "F10=Save"
- #language fr-FR "F10=Économiser"
-#string SAVE_FAILED #language en-US "Failed to Save"
- #language fr-FR "Échouer à économiser"
-#string NO_SUBMIT_IF_CHECK_FAILED #language en-US "NO_SUBMIT_IF check fail."
- #language fr-FR "NO_SUBMIT_IF check fail."
-#string ADJUST_HELP_PAGE_DOWN #language en-US "More (D/d)"
- #language fr-FR "More (D/d)"
-#string ADJUST_HELP_PAGE_UP #language en-US "More (U/u)"
- #language fr-FR "More (U/u)"
-#string PROMPT_FOR_PASSWORD #language en-US "Please type in your password"
- #language fr-FR "S'il vous plaît tape votre mot de passe"
-#string PROMPT_FOR_NEW_PASSWORD #language en-US "Please type in your new password"
- #language fr-FR "S'il vous plaît tape votre nouveau mot de passe"
-#string CONFIRM_PASSWORD #language en-US "Please confirm your new password"
- #language fr-FR "S'il vous plaît confirmer votre nouveau mot de passe"
-#string CONFIRM_ERROR #language en-US "Passwords are not the same"
- #language fr-FR "Les mots de passe ne sont pas pareils"
-#string PASSWORD_INVALID #language en-US "Incorrect password"
- #language fr-FR "Mauvais mot de passe"
-#string PRESS_ENTER #language en-US "Press ENTER to continue"
- #language fr-FR "La presse ENTRE continuer"
-#string PROMPT_FOR_DATA #language en-US "Please type in your data"
- #language fr-FR "S'il vous plaît tape vos données"
-#string EMPTY_STRING #language en-US ""
- #language fr-FR ""
-#string MINI_STRING #language en-US "Please enter enough characters"
- #language fr-FR "Veuillez écrire assez de caractères"
-#string OPTION_MISMATCH #language en-US "Question value mismatch with Option value!"
- #language fr-FR "Question valeur décalage avec l'option valeur!"
-#string FORM_SUPPRESSED #language en-US "Form is suppressed. Nothing is displayed."
- #language fr-FR "Form is suppressed. Nothing is displayed."
-#string PROTOCOL_NOT_FOUND #language en-US "Convert string to device path fail. Can't goto the destination."
- #language fr-FR "Convert string to device path fail. Can't goto the destination."
-#string DISCARD_OR_JUMP #language en-US "Press D(d) to discard changes for this form, Press G(g) to go to this form"
- #language fr-FR "Press D(d) to discard changes for this form, Press G(g) to go to this form"
-#string DISCARD_OR_JUMP_DISCARD #language en-US "D (d)"
- #language fr-FR "D (d)"
-#string DISCARD_OR_JUMP_JUMP #language en-US "G (g)"
- #language fr-FR "G (g)"
-#string DISCARD_OR_CHECK #language en-US "Press D(d) to discard changes for this form, Press C(c) to check the error"
- #language fr-FR "Press D(d) to discard changes for this form, Press C(c) to check the error"
-#string DISCARD_OR_CHECK_CHECK #language en-US "C (c)"
- #language fr-FR "C (c)"
-#string CONFIRM_DISCARD_MESSAGE #language en-US "Discard configuration changes"
- #language fr-FR "Discard configuration changes"
-#string CONFIRM_DEFAULT_MESSAGE #language en-US "Load default configuration"
- #language fr-FR "Load default configuration"
-#string CONFIRM_DEFAULT_MESSAGE_2ND #language en-US "load default configuration"
- #language fr-FR "load default configuration"
-#string CONFIRM_SUBMIT_MESSAGE #language en-US "Save configuration changes"
- #language fr-FR "Save configuration changes"
-#string CONFIRM_SUBMIT_MESSAGE_2ND #language en-US "save configuration changes"
- #language fr-FR "save configuration changes"
-#string CONFIRM_RESET_MESSAGE #language en-US "Reset"
- #language fr-FR "Reset"
-#string CONFIRM_RESET_MESSAGE_2ND #language en-US "reset"
- #language fr-FR "reset"
-#string CONFIRM_EXIT_MESSAGE #language en-US "Exit"
- #language fr-FR "Exit"
-#string CONFIRM_EXIT_MESSAGE_2ND #language en-US "exit"
- #language fr-FR "exit"
-#string CONFIRM_OPTION #language en-US "Press 'Y' to confirm, 'N'/'ESC' to ignore."
- #language fr-FR "Press 'Y' to confirm, 'N'/'ESC' to ignore."
-#string CONFIRM_OPTION_YES #language en-US "Y (y)"
- #language fr-FR "Y (y)"
-#string CONFIRM_OPTION_NO #language en-US "N (n)"
- #language fr-FR "N (n)"
-#string CONFIRM_OPTION_OK #language en-US "O (o)"
- #language fr-FR "O (o)"
-#string CONFIRM_OPTION_CANCEL #language en-US "C (c)"
- #language fr-FR "C (c)"
-#string CONFIRM_OPTION_CONNECT #language en-US " and "
- #language fr-FR " and "
-#string CONFIRM_OPTION_END #language en-US "?"
- #language fr-FR "?"
-#string RECONNECT_FAILED #language en-US "Reconnect the controller failed!"
- #language fr-FR "Reconnect the controller failed!"
-#string RECONNECT_CONFIRM_CHANGES #language en-US "Reconnect is required, confirm the changes then exit and reconnect"
- #language fr-FR "Reconnect is required, confirm the changes then exit and reconnect"
-#string RECONNECT_CHANGES_OPTIONS #language en-US "Press 'Y' to save, 'N' to discard"
- #language fr-FR "Press 'Y' to save, 'N' to discard"
-#string RECONNECT_REQUIRED #language en-US "Reconnect is required, exit and reconnect"
- #language fr-FR "Reconnect is required, exit and reconnect"
-#string GET_TIME_FAIL #language en-US " Get date/time fail, display ??."
- #language fr-FR " Get data/time fail, display ??."
-#string PASSWORD_NOT_SUPPORTED #language en-US "Unsupported! Because no interactieve flag or no ConfigAccess protocol!"
- #language fr-FR "Unsupported! Because no interactieve flag or no ConfigAccess protocol!"
-#string OK_SELECTABLE_OPTION #language en-US "[ Ok ]"
- #language fr-FR "[ Ok ]"
-#string CANCEL_SELECTABLE_OPTION #language en-US "[Cancel]"
- #language fr-FR "[Cancel]"
-#string YES_SELECTABLE_OPTION #language en-US "[ Yes ]"
- #language fr-FR "[ Yes ]"
-#string NO_SELECTABLE_OPTION #language en-US "[ No ]"
- #language fr-FR "[ No ]"
-#string ERROR_POPUP_STRING #language en-US "ERROR"
- #language fr-FR "ERROR"
-#string WARNING_POPUP_STRING #language en-US "WARNING"
- #language fr-FR "WARNING"
-#string INFO_POPUP_STRING #language en-US "INFO"
- #language fr-FR "INFO"
-
+// *++ +// +// Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// SetupBrowserStr.uni +// +// Abstract: +// +// String definitions for Browser. +// +// --*/ + + +/=# + +#langdef en-US "English" +#langdef fr-FR "Français" + +#string UNKNOWN_STRING #language en-US "!" + #language fr-FR "!" +#string STATUS_BROWSER_ERROR #language en-US "Browser met some error, return!" + #language fr-FR "Browser met some error, return!" +#string STATUS_BROWSER_FORM_NOT_FOUND #language en-US "Form not found, return!" + #language fr-FR "Form not found, return!" +#string STATUS_BROWSER_NO_SUBMIT_IF #language en-US "Not allowed to submit, return!" + #language fr-FR "Not allowed to submit, return!" +#string FUNCTION_NINE_STRING #language en-US "F9=Reset to Defaults" + #language fr-FR "F9=Reset à Défauts" +#string FUNCTION_TEN_STRING #language en-US "F10=Save" + #language fr-FR "F10=Économiser" +#string SAVE_FAILED #language en-US "Failed to Save" + #language fr-FR "Échouer à économiser" +#string NO_SUBMIT_IF_CHECK_FAILED #language en-US "NO_SUBMIT_IF check fail." + #language fr-FR "NO_SUBMIT_IF check fail." +#string ADJUST_HELP_PAGE_DOWN #language en-US "More (D/d)" + #language fr-FR "More (D/d)" +#string ADJUST_HELP_PAGE_UP #language en-US "More (U/u)" + #language fr-FR "More (U/u)" +#string PROMPT_FOR_PASSWORD #language en-US "Please type in your password" + #language fr-FR "S'il vous plaît tape votre mot de passe" +#string PROMPT_FOR_NEW_PASSWORD #language en-US "Please type in your new password" + #language fr-FR "S'il vous plaît tape votre nouveau mot de passe" +#string CONFIRM_PASSWORD #language en-US "Please confirm your new password" + #language fr-FR "S'il vous plaît confirmer votre nouveau mot de passe" +#string CONFIRM_ERROR #language en-US "Passwords are not the same" + #language fr-FR "Les mots de passe ne sont pas pareils" +#string PASSWORD_INVALID #language en-US "Incorrect password" + #language fr-FR "Mauvais mot de passe" +#string PRESS_ENTER #language en-US "Press ENTER to continue" + #language fr-FR "La presse ENTRE continuer" +#string PROMPT_FOR_DATA #language en-US "Please type in your data" + #language fr-FR "S'il vous plaît tape vos données" +#string EMPTY_STRING #language en-US "" + #language fr-FR "" +#string MINI_STRING #language en-US "Please enter enough characters" + #language fr-FR "Veuillez écrire assez de caractères" +#string OPTION_MISMATCH #language en-US "Question value mismatch with Option value!" + #language fr-FR "Question valeur décalage avec l'option valeur!" +#string FORM_SUPPRESSED #language en-US "Form is suppressed. Nothing is displayed." + #language fr-FR "Form is suppressed. Nothing is displayed." +#string PROTOCOL_NOT_FOUND #language en-US "Convert string to device path fail. Can't goto the destination." + #language fr-FR "Convert string to device path fail. Can't goto the destination." +#string DISCARD_OR_JUMP #language en-US "Press D(d) to discard changes for this form, Press G(g) to go to this form" + #language fr-FR "Press D(d) to discard changes for this form, Press G(g) to go to this form" +#string DISCARD_OR_JUMP_DISCARD #language en-US "D (d)" + #language fr-FR "D (d)" +#string DISCARD_OR_JUMP_JUMP #language en-US "G (g)" + #language fr-FR "G (g)" +#string DISCARD_OR_CHECK #language en-US "Press D(d) to discard changes for this form, Press C(c) to check the error" + #language fr-FR "Press D(d) to discard changes for this form, Press C(c) to check the error" +#string DISCARD_OR_CHECK_CHECK #language en-US "C (c)" + #language fr-FR "C (c)" +#string CONFIRM_DISCARD_MESSAGE #language en-US "Discard configuration changes" + #language fr-FR "Discard configuration changes" +#string CONFIRM_DEFAULT_MESSAGE #language en-US "Load default configuration" + #language fr-FR "Load default configuration" +#string CONFIRM_DEFAULT_MESSAGE_2ND #language en-US "load default configuration" + #language fr-FR "load default configuration" +#string CONFIRM_SUBMIT_MESSAGE #language en-US "Save configuration changes" + #language fr-FR "Save configuration changes" +#string CONFIRM_SUBMIT_MESSAGE_2ND #language en-US "save configuration changes" + #language fr-FR "save configuration changes" +#string CONFIRM_RESET_MESSAGE #language en-US "Reset" + #language fr-FR "Reset" +#string CONFIRM_RESET_MESSAGE_2ND #language en-US "reset" + #language fr-FR "reset" +#string CONFIRM_EXIT_MESSAGE #language en-US "Exit" + #language fr-FR "Exit" +#string CONFIRM_EXIT_MESSAGE_2ND #language en-US "exit" + #language fr-FR "exit" +#string CONFIRM_OPTION #language en-US "Press 'Y' to confirm, 'N'/'ESC' to ignore." + #language fr-FR "Press 'Y' to confirm, 'N'/'ESC' to ignore." +#string CONFIRM_OPTION_YES #language en-US "Y (y)" + #language fr-FR "Y (y)" +#string CONFIRM_OPTION_NO #language en-US "N (n)" + #language fr-FR "N (n)" +#string CONFIRM_OPTION_OK #language en-US "O (o)" + #language fr-FR "O (o)" +#string CONFIRM_OPTION_CANCEL #language en-US "C (c)" + #language fr-FR "C (c)" +#string CONFIRM_OPTION_CONNECT #language en-US " and " + #language fr-FR " and " +#string CONFIRM_OPTION_END #language en-US "?" + #language fr-FR "?" +#string RECONNECT_FAILED #language en-US "Reconnect the controller failed!" + #language fr-FR "Reconnect the controller failed!" +#string RECONNECT_CONFIRM_CHANGES #language en-US "Reconnect is required, confirm the changes then exit and reconnect" + #language fr-FR "Reconnect is required, confirm the changes then exit and reconnect" +#string RECONNECT_CHANGES_OPTIONS #language en-US "Press 'Y' to save, 'N' to discard" + #language fr-FR "Press 'Y' to save, 'N' to discard" +#string RECONNECT_REQUIRED #language en-US "Reconnect is required, exit and reconnect" + #language fr-FR "Reconnect is required, exit and reconnect" +#string GET_TIME_FAIL #language en-US " Get date/time fail, display ??." + #language fr-FR " Get data/time fail, display ??." +#string PASSWORD_NOT_SUPPORTED #language en-US "Unsupported! Because no interactieve flag or no ConfigAccess protocol!" + #language fr-FR "Unsupported! Because no interactieve flag or no ConfigAccess protocol!" +#string OK_SELECTABLE_OPTION #language en-US "[ Ok ]" + #language fr-FR "[ Ok ]" +#string CANCEL_SELECTABLE_OPTION #language en-US "[Cancel]" + #language fr-FR "[Cancel]" +#string YES_SELECTABLE_OPTION #language en-US "[ Yes ]" + #language fr-FR "[ Yes ]" +#string NO_SELECTABLE_OPTION #language en-US "[ No ]" + #language fr-FR "[ No ]" +#string ERROR_POPUP_STRING #language en-US "ERROR" + #language fr-FR "ERROR" +#string WARNING_POPUP_STRING #language en-US "WARNING" + #language fr-FR "WARNING" +#string INFO_POPUP_STRING #language en-US "INFO" + #language fr-FR "INFO" + diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c b/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c index f70feeb55f..8f35c9b4ed 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c +++ b/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c @@ -1,1692 +1,1692 @@ -/** @file
-Implementation for handling user input from the User Interfaces.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FormDisplay.h"
-
-/**
- Get maximum and minimum info from this opcode.
-
- @param OpCode Pointer to the current input opcode.
- @param Minimum The minimum size info for this opcode.
- @param Maximum The maximum size info for this opcode.
-
-**/
-VOID
-GetFieldFromOp (
- IN EFI_IFR_OP_HEADER *OpCode,
- OUT UINTN *Minimum,
- OUT UINTN *Maximum
- )
-{
- EFI_IFR_STRING *StringOp;
- EFI_IFR_PASSWORD *PasswordOp;
-
- if (OpCode->OpCode == EFI_IFR_STRING_OP) {
- StringOp = (EFI_IFR_STRING *)OpCode;
- *Minimum = StringOp->MinSize;
- *Maximum = StringOp->MaxSize;
- } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
- PasswordOp = (EFI_IFR_PASSWORD *)OpCode;
- *Minimum = PasswordOp->MinSize;
- *Maximum = PasswordOp->MaxSize;
- } else {
- *Minimum = 0;
- *Maximum = 0;
- }
-}
-
-/**
- Get string or password input from user.
-
- @param MenuOption Pointer to the current input menu.
- @param Prompt The prompt string shown on popup window.
- @param StringPtr Old user input and destination for use input string.
-
- @retval EFI_SUCCESS If string input is read successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-ReadString (
- IN UI_MENU_OPTION *MenuOption,
- IN CHAR16 *Prompt,
- IN OUT CHAR16 *StringPtr
- )
-{
- EFI_STATUS Status;
- EFI_INPUT_KEY Key;
- CHAR16 NullCharacter;
- UINTN ScreenSize;
- CHAR16 Space[2];
- CHAR16 KeyPad[2];
- CHAR16 *TempString;
- CHAR16 *BufferedString;
- UINTN Index;
- UINTN Index2;
- UINTN Count;
- UINTN Start;
- UINTN Top;
- UINTN DimensionsWidth;
- UINTN DimensionsHeight;
- UINTN CurrentCursor;
- BOOLEAN CursorVisible;
- UINTN Minimum;
- UINTN Maximum;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- BOOLEAN IsPassword;
- UINTN MaxLen;
-
- DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
- DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
-
- NullCharacter = CHAR_NULL;
- ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);
- Space[0] = L' ';
- Space[1] = CHAR_NULL;
-
- Question = MenuOption->ThisTag;
- GetFieldFromOp (Question->OpCode, &Minimum, &Maximum);
-
- if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
- IsPassword = TRUE;
- } else {
- IsPassword = FALSE;
- }
-
- MaxLen = Maximum + 1;
- TempString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (TempString);
-
- if (ScreenSize < (Maximum + 1)) {
- ScreenSize = Maximum + 1;
- }
-
- if ((ScreenSize + 2) > DimensionsWidth) {
- ScreenSize = DimensionsWidth - 2;
- }
-
- BufferedString = AllocateZeroPool (ScreenSize * 2);
- ASSERT (BufferedString);
-
- Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;
- Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;
-
- //
- // Display prompt for string
- //
- // CreateDialog (NULL, "", Prompt, Space, "", NULL);
- CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
-
- CursorVisible = gST->ConOut->Mode->CursorVisible;
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-
- CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
- if (CurrentCursor != 0) {
- //
- // Show the string which has beed saved before.
- //
- SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
- PrintStringAt (Start + 1, Top + 3, BufferedString);
-
- if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
- Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
- } else {
- Index = 0;
- }
-
- if (IsPassword) {
- gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
- }
-
- for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
- BufferedString[Count] = StringPtr[Index];
-
- if (IsPassword) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
- }
- }
-
- if (!IsPassword) {
- PrintStringAt (Start + 1, Top + 3, BufferedString);
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
- }
-
- do {
- Status = WaitForKeyStroke (&Key);
- ASSERT_EFI_ERROR (Status);
-
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
- switch (Key.UnicodeChar) {
- case CHAR_NULL:
- switch (Key.ScanCode) {
- case SCAN_LEFT:
- if (CurrentCursor > 0) {
- CurrentCursor--;
- }
-
- break;
-
- case SCAN_RIGHT:
- if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
- CurrentCursor++;
- }
-
- break;
-
- case SCAN_ESC:
- FreePool (TempString);
- FreePool (BufferedString);
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
- return EFI_DEVICE_ERROR;
-
- case SCAN_DELETE:
- for (Index = CurrentCursor; StringPtr[Index] != CHAR_NULL; Index++) {
- StringPtr[Index] = StringPtr[Index + 1];
- PrintCharAt (Start + Index + 1, Top + 3, IsPassword && StringPtr[Index] != CHAR_NULL ? L'*' : StringPtr[Index]);
- }
-
- break;
-
- default:
- break;
- }
-
- break;
-
- case CHAR_CARRIAGE_RETURN:
- if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
- FreePool (TempString);
- FreePool (BufferedString);
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
- return EFI_SUCCESS;
- } else {
- //
- // Simply create a popup to tell the user that they had typed in too few characters.
- // To save code space, we can then treat this as an error and return back to the menu.
- //
- do {
- CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- FreePool (TempString);
- FreePool (BufferedString);
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
- return EFI_DEVICE_ERROR;
- }
-
- case CHAR_BACKSPACE:
- if ((StringPtr[0] != CHAR_NULL) && (CurrentCursor != 0)) {
- for (Index = 0; Index < CurrentCursor - 1; Index++) {
- TempString[Index] = StringPtr[Index];
- }
-
- Count = GetStringWidth (StringPtr) / 2 - 1;
- if (Count >= CurrentCursor) {
- for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {
- TempString[Index] = StringPtr[Index2];
- }
-
- TempString[Index] = CHAR_NULL;
- }
-
- //
- // Effectively truncate string by 1 character
- //
- StrCpyS (StringPtr, MaxLen, TempString);
- CurrentCursor--;
- }
-
- default:
- //
- // If it is the beginning of the string, don't worry about checking maximum limits
- //
- if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
- StrnCpyS (StringPtr, MaxLen, &Key.UnicodeChar, 1);
- CurrentCursor++;
- } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
- KeyPad[0] = Key.UnicodeChar;
- KeyPad[1] = CHAR_NULL;
- Count = GetStringWidth (StringPtr) / 2 - 1;
- if (CurrentCursor < Count) {
- for (Index = 0; Index < CurrentCursor; Index++) {
- TempString[Index] = StringPtr[Index];
- }
-
- TempString[Index] = CHAR_NULL;
- StrCatS (TempString, MaxLen, KeyPad);
- StrCatS (TempString, MaxLen, StringPtr + CurrentCursor);
- StrCpyS (StringPtr, MaxLen, TempString);
- } else {
- StrCatS (StringPtr, MaxLen, KeyPad);
- }
-
- CurrentCursor++;
- }
-
- //
- // If the width of the input string is now larger than the screen, we nee to
- // adjust the index to start printing portions of the string
- //
- SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
- PrintStringAt (Start + 1, Top + 3, BufferedString);
-
- if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
- Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
- } else {
- Index = 0;
- }
-
- if (IsPassword) {
- gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
- }
-
- for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
- BufferedString[Count] = StringPtr[Index];
-
- if (IsPassword) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
- }
- }
-
- if (!IsPassword) {
- PrintStringAt (Start + 1, Top + 3, BufferedString);
- }
-
- break;
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
- } while (TRUE);
-}
-
-/**
- Adjust the value to the correct one. Rules follow the sample:
- like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
- Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
-
- @param QuestionValue Pointer to current question.
- @param Sequence The sequence of the field in the question.
-**/
-VOID
-AdjustQuestionValue (
- IN EFI_HII_VALUE *QuestionValue,
- IN UINT8 Sequence
- )
-{
- UINT8 Month;
- UINT16 Year;
- UINT8 Maximum;
- UINT8 Minimum;
-
- Month = QuestionValue->Value.date.Month;
- Year = QuestionValue->Value.date.Year;
- Minimum = 1;
-
- switch (Month) {
- case 2:
- if (((Year % 4) == 0) && (((Year % 100) != 0) || ((Year % 400) == 0))) {
- Maximum = 29;
- } else {
- Maximum = 28;
- }
-
- break;
- case 4:
- case 6:
- case 9:
- case 11:
- Maximum = 30;
- break;
- default:
- Maximum = 31;
- break;
- }
-
- //
- // Change the month area.
- //
- if (Sequence == 0) {
- if (QuestionValue->Value.date.Day > Maximum) {
- QuestionValue->Value.date.Day = Maximum;
- }
- }
-
- //
- // Change the Year area.
- //
- if (Sequence == 2) {
- if (QuestionValue->Value.date.Day > Maximum) {
- QuestionValue->Value.date.Day = Minimum;
- }
- }
-}
-
-/**
- Get field info from numeric opcode.
-
- @param OpCode Pointer to the current input opcode.
- @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
- @param QuestionValue Input question value, with EFI_HII_VALUE type.
- @param Value Return question value, always return UINT64 type.
- @param Minimum The minimum size info for this opcode.
- @param Maximum The maximum size info for this opcode.
- @param Step The step size info for this opcode.
- @param StorageWidth The storage width info for this opcode.
-
-**/
-VOID
-GetValueFromNum (
- IN EFI_IFR_OP_HEADER *OpCode,
- IN BOOLEAN IntInput,
- IN EFI_HII_VALUE *QuestionValue,
- OUT UINT64 *Value,
- OUT UINT64 *Minimum,
- OUT UINT64 *Maximum,
- OUT UINT64 *Step,
- OUT UINT16 *StorageWidth
- )
-{
- EFI_IFR_NUMERIC *NumericOp;
-
- NumericOp = (EFI_IFR_NUMERIC *)OpCode;
-
- switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
- case EFI_IFR_NUMERIC_SIZE_1:
- if (IntInput) {
- *Minimum = (INT64)(INT8)NumericOp->data.u8.MinValue;
- *Maximum = (INT64)(INT8)NumericOp->data.u8.MaxValue;
- *Value = (INT64)(INT8)QuestionValue->Value.u8;
- } else {
- *Minimum = NumericOp->data.u8.MinValue;
- *Maximum = NumericOp->data.u8.MaxValue;
- *Value = QuestionValue->Value.u8;
- }
-
- *Step = NumericOp->data.u8.Step;
- *StorageWidth = (UINT16)sizeof (UINT8);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_2:
- if (IntInput) {
- *Minimum = (INT64)(INT16)NumericOp->data.u16.MinValue;
- *Maximum = (INT64)(INT16)NumericOp->data.u16.MaxValue;
- *Value = (INT64)(INT16)QuestionValue->Value.u16;
- } else {
- *Minimum = NumericOp->data.u16.MinValue;
- *Maximum = NumericOp->data.u16.MaxValue;
- *Value = QuestionValue->Value.u16;
- }
-
- *Step = NumericOp->data.u16.Step;
- *StorageWidth = (UINT16)sizeof (UINT16);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_4:
- if (IntInput) {
- *Minimum = (INT64)(INT32)NumericOp->data.u32.MinValue;
- *Maximum = (INT64)(INT32)NumericOp->data.u32.MaxValue;
- *Value = (INT64)(INT32)QuestionValue->Value.u32;
- } else {
- *Minimum = NumericOp->data.u32.MinValue;
- *Maximum = NumericOp->data.u32.MaxValue;
- *Value = QuestionValue->Value.u32;
- }
-
- *Step = NumericOp->data.u32.Step;
- *StorageWidth = (UINT16)sizeof (UINT32);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_8:
- if (IntInput) {
- *Minimum = (INT64)NumericOp->data.u64.MinValue;
- *Maximum = (INT64)NumericOp->data.u64.MaxValue;
- *Value = (INT64)QuestionValue->Value.u64;
- } else {
- *Minimum = NumericOp->data.u64.MinValue;
- *Maximum = NumericOp->data.u64.MaxValue;
- *Value = QuestionValue->Value.u64;
- }
-
- *Step = NumericOp->data.u64.Step;
- *StorageWidth = (UINT16)sizeof (UINT64);
- break;
-
- default:
- break;
- }
-
- if (*Maximum == 0) {
- *Maximum = (UINT64)-1;
- }
-}
-
-/**
- This routine reads a numeric value from the user input.
-
- @param MenuOption Pointer to the current input menu.
-
- @retval EFI_SUCCESS If numerical input is read successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-GetNumericInput (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- UINTN Column;
- UINTN Row;
- CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];
- CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
- UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
- UINTN Count;
- UINTN Loop;
- BOOLEAN ManualInput;
- BOOLEAN HexInput;
- BOOLEAN IntInput;
- BOOLEAN Negative;
- BOOLEAN ValidateFail;
- BOOLEAN DateOrTime;
- UINTN InputWidth;
- UINT64 EditValue;
- UINT64 Step;
- UINT64 Minimum;
- UINT64 Maximum;
- UINTN EraseLen;
- UINT8 Digital;
- EFI_INPUT_KEY Key;
- EFI_HII_VALUE *QuestionValue;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- EFI_IFR_NUMERIC *NumericOp;
- UINT16 StorageWidth;
-
- Column = MenuOption->OptCol;
- Row = MenuOption->Row;
- PreviousNumber[0] = 0;
- Count = 0;
- InputWidth = 0;
- Digital = 0;
- StorageWidth = 0;
- Minimum = 0;
- Maximum = 0;
- NumericOp = NULL;
- IntInput = FALSE;
- HexInput = FALSE;
- Negative = FALSE;
- ValidateFail = FALSE;
-
- Question = MenuOption->ThisTag;
- QuestionValue = &Question->CurrentValue;
- ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16));
-
- //
- // Only two case, user can enter to this function: Enter and +/- case.
- // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
- //
- ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
-
- if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
- DateOrTime = TRUE;
- } else {
- DateOrTime = FALSE;
- }
-
- //
- // Prepare Value to be edit
- //
- EraseLen = 0;
- EditValue = 0;
- if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
- Step = 1;
- Minimum = 1;
-
- switch (MenuOption->Sequence) {
- case 0:
- Maximum = 12;
- EraseLen = 4;
- EditValue = QuestionValue->Value.date.Month;
- break;
-
- case 1:
- switch (QuestionValue->Value.date.Month) {
- case 2:
- if (((QuestionValue->Value.date.Year % 4) == 0) &&
- (((QuestionValue->Value.date.Year % 100) != 0) ||
- ((QuestionValue->Value.date.Year % 400) == 0)))
- {
- Maximum = 29;
- } else {
- Maximum = 28;
- }
-
- break;
- case 4:
- case 6:
- case 9:
- case 11:
- Maximum = 30;
- break;
- default:
- Maximum = 31;
- break;
- }
-
- EraseLen = 3;
- EditValue = QuestionValue->Value.date.Day;
- break;
-
- case 2:
- Maximum = 0xffff;
- EraseLen = 5;
- EditValue = QuestionValue->Value.date.Year;
- break;
-
- default:
- break;
- }
- } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
- Step = 1;
- Minimum = 0;
-
- switch (MenuOption->Sequence) {
- case 0:
- Maximum = 23;
- EraseLen = 4;
- EditValue = QuestionValue->Value.time.Hour;
- break;
-
- case 1:
- Maximum = 59;
- EraseLen = 3;
- EditValue = QuestionValue->Value.time.Minute;
- break;
-
- case 2:
- Maximum = 59;
- EraseLen = 3;
- EditValue = QuestionValue->Value.time.Second;
- break;
-
- default:
- break;
- }
- } else {
- ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);
- NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode;
- GetValueFromNum (Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);
- EraseLen = gOptionBlockWidth;
- }
-
- if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {
- if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX) {
- HexInput = TRUE;
- } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0) {
- //
- // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
- //
- IntInput = TRUE;
- }
- }
-
- //
- // Enter from "Enter" input, clear the old word showing.
- //
- if (ManualInput) {
- if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
- if (HexInput) {
- InputWidth = StorageWidth * 2;
- } else {
- switch (StorageWidth) {
- case 1:
- InputWidth = 3;
- break;
-
- case 2:
- InputWidth = 5;
- break;
-
- case 4:
- InputWidth = 10;
- break;
-
- case 8:
- InputWidth = 20;
- break;
-
- default:
- InputWidth = 0;
- break;
- }
-
- if (IntInput) {
- //
- // Support an extra '-' for negative number.
- //
- InputWidth += 1;
- }
- }
-
- InputText[0] = LEFT_NUMERIC_DELIMITER;
- SetUnicodeMem (InputText + 1, InputWidth, L' ');
- ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
- InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
- InputText[InputWidth + 2] = L'\0';
-
- PrintStringAt (Column, Row, InputText);
- Column++;
- }
-
- if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
- if (MenuOption->Sequence == 2) {
- InputWidth = 4;
- } else {
- InputWidth = 2;
- }
-
- if (MenuOption->Sequence == 0) {
- InputText[0] = LEFT_NUMERIC_DELIMITER;
- SetUnicodeMem (InputText + 1, InputWidth, L' ');
- InputText[InputWidth + 1] = DATE_SEPARATOR;
- InputText[InputWidth + 2] = L'\0';
- } else if (MenuOption->Sequence == 1) {
- SetUnicodeMem (InputText, InputWidth, L' ');
- InputText[InputWidth] = DATE_SEPARATOR;
- InputText[InputWidth + 1] = L'\0';
- } else {
- SetUnicodeMem (InputText, InputWidth, L' ');
- InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
- InputText[InputWidth + 1] = L'\0';
- }
-
- PrintStringAt (Column, Row, InputText);
- if (MenuOption->Sequence == 0) {
- Column++;
- }
- }
-
- if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
- InputWidth = 2;
-
- if (MenuOption->Sequence == 0) {
- InputText[0] = LEFT_NUMERIC_DELIMITER;
- SetUnicodeMem (InputText + 1, InputWidth, L' ');
- InputText[InputWidth + 1] = TIME_SEPARATOR;
- InputText[InputWidth + 2] = L'\0';
- } else if (MenuOption->Sequence == 1) {
- SetUnicodeMem (InputText, InputWidth, L' ');
- InputText[InputWidth] = TIME_SEPARATOR;
- InputText[InputWidth + 1] = L'\0';
- } else {
- SetUnicodeMem (InputText, InputWidth, L' ');
- InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
- InputText[InputWidth + 1] = L'\0';
- }
-
- PrintStringAt (Column, Row, InputText);
- if (MenuOption->Sequence == 0) {
- Column++;
- }
- }
- }
-
- //
- // First time we enter this handler, we need to check to see if
- // we were passed an increment or decrement directive
- //
- do {
- Key.UnicodeChar = CHAR_NULL;
- if (gDirection != 0) {
- Key.ScanCode = gDirection;
- gDirection = 0;
- goto TheKey2;
- }
-
- WaitForKeyStroke (&Key);
-
-TheKey2:
- switch (Key.UnicodeChar) {
- case '+':
- case '-':
- if (ManualInput && IntInput) {
- //
- // In Manual input mode, check whether input the negative flag.
- //
- if (Key.UnicodeChar == '-') {
- if (Negative) {
- break;
- }
-
- Negative = TRUE;
- PrintCharAt (Column++, Row, Key.UnicodeChar);
- }
- } else {
- if (Key.UnicodeChar == '+') {
- Key.ScanCode = SCAN_RIGHT;
- } else {
- Key.ScanCode = SCAN_LEFT;
- }
-
- Key.UnicodeChar = CHAR_NULL;
- goto TheKey2;
- }
-
- break;
-
- case CHAR_NULL:
- switch (Key.ScanCode) {
- case SCAN_LEFT:
- case SCAN_RIGHT:
- if (DateOrTime && !ManualInput) {
- //
- // By setting this value, we will return back to the caller.
- // We need to do this since an auto-refresh will destroy the adjustment
- // based on what the real-time-clock is showing. So we always commit
- // upon changing the value.
- //
- gDirection = SCAN_DOWN;
- }
-
- if ((Step != 0) && !ManualInput) {
- if (Key.ScanCode == SCAN_LEFT) {
- if (IntInput) {
- if ((INT64)EditValue >= (INT64)Minimum + (INT64)Step) {
- EditValue = EditValue - Step;
- } else if ((INT64)EditValue > (INT64)Minimum) {
- EditValue = Minimum;
- } else {
- EditValue = Maximum;
- }
- } else {
- if (EditValue >= Minimum + Step) {
- EditValue = EditValue - Step;
- } else if (EditValue > Minimum) {
- EditValue = Minimum;
- } else {
- EditValue = Maximum;
- }
- }
- } else if (Key.ScanCode == SCAN_RIGHT) {
- if (IntInput) {
- if ((INT64)EditValue + (INT64)Step <= (INT64)Maximum) {
- EditValue = EditValue + Step;
- } else if ((INT64)EditValue < (INT64)Maximum) {
- EditValue = Maximum;
- } else {
- EditValue = Minimum;
- }
- } else {
- if (EditValue + Step <= Maximum) {
- EditValue = EditValue + Step;
- } else if (EditValue < Maximum) {
- EditValue = Maximum;
- } else {
- EditValue = Minimum;
- }
- }
- }
-
- ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
- if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
- if (MenuOption->Sequence == 2) {
- //
- // Year
- //
- UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16)EditValue);
- } else {
- //
- // Month/Day
- //
- UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
- }
-
- if (MenuOption->Sequence == 0) {
- ASSERT (EraseLen >= 2);
- FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
- } else if (MenuOption->Sequence == 1) {
- ASSERT (EraseLen >= 1);
- FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
- }
- } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
- UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
-
- if (MenuOption->Sequence == 0) {
- ASSERT (EraseLen >= 2);
- FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
- } else if (MenuOption->Sequence == 1) {
- ASSERT (EraseLen >= 1);
- FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
- }
- } else {
- QuestionValue->Value.u64 = EditValue;
- PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
- for (Loop = 0; Loop < EraseLen; Loop++) {
- PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
-
- if (MenuOption->Sequence == 0) {
- PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
- Column = MenuOption->OptCol + 1;
- }
-
- PrintStringAt (Column, Row, FormattedNumber);
-
- if (!DateOrTime || (MenuOption->Sequence == 2)) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
- }
- }
-
- goto EnterCarriageReturn;
-
- case SCAN_UP:
- case SCAN_DOWN:
- goto EnterCarriageReturn;
-
- case SCAN_ESC:
- return EFI_DEVICE_ERROR;
-
- default:
- break;
- }
-
- break;
-
-EnterCarriageReturn:
-
- case CHAR_CARRIAGE_RETURN:
- //
- // Validate input value with Minimum value.
- //
- ValidateFail = FALSE;
- if (IntInput) {
- //
- // After user input Enter, need to check whether the input value.
- // If input a negative value, should compare with maximum value.
- // else compare with the minimum value.
- //
- if (Negative) {
- ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
- } else {
- ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
- }
-
- if (ValidateFail) {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- break;
- }
- } else if (EditValue < Minimum) {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- break;
- }
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
- CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
- QuestionValue = &gUserInput->InputValue;
- //
- // Store Edit value back to Question
- //
- if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
- switch (MenuOption->Sequence) {
- case 0:
- QuestionValue->Value.date.Month = (UINT8)EditValue;
- break;
-
- case 1:
- QuestionValue->Value.date.Day = (UINT8)EditValue;
- break;
-
- case 2:
- QuestionValue->Value.date.Year = (UINT16)EditValue;
- break;
-
- default:
- break;
- }
- } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
- switch (MenuOption->Sequence) {
- case 0:
- QuestionValue->Value.time.Hour = (UINT8)EditValue;
- break;
-
- case 1:
- QuestionValue->Value.time.Minute = (UINT8)EditValue;
- break;
-
- case 2:
- QuestionValue->Value.time.Second = (UINT8)EditValue;
- break;
-
- default:
- break;
- }
- } else {
- //
- // Numeric
- //
- QuestionValue->Value.u64 = EditValue;
- }
-
- //
- // Adjust the value to the correct one.
- // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
- // 2013.03.29 -> 2013.02.29 -> 2013.02.28
- //
- if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) &&
- ((MenuOption->Sequence == 0) || (MenuOption->Sequence == 2)))
- {
- AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
- }
-
- return EFI_SUCCESS;
-
- case CHAR_BACKSPACE:
- if (ManualInput) {
- if (Count == 0) {
- if (Negative) {
- Negative = FALSE;
- Column--;
- PrintStringAt (Column, Row, L" ");
- }
-
- break;
- }
-
- //
- // Remove a character
- //
- EditValue = PreviousNumber[Count - 1];
- UpdateStatusBar (INPUT_ERROR, FALSE);
- Count--;
- Column--;
- PrintStringAt (Column, Row, L" ");
- }
-
- break;
-
- default:
- if (ManualInput) {
- if (HexInput) {
- if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
- Digital = (UINT8)(Key.UnicodeChar - L'0');
- } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
- Digital = (UINT8)(Key.UnicodeChar - L'A' + 0x0A);
- } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
- Digital = (UINT8)(Key.UnicodeChar - L'a' + 0x0A);
- } else {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- break;
- }
- } else {
- if ((Key.UnicodeChar > L'9') || (Key.UnicodeChar < L'0')) {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- break;
- }
- }
-
- //
- // If Count exceed input width, there is no way more is valid
- //
- if (Count >= InputWidth) {
- break;
- }
-
- //
- // Someone typed something valid!
- //
- if (Count != 0) {
- if (HexInput) {
- EditValue = LShiftU64 (EditValue, 4) + Digital;
- } else if (IntInput && Negative) {
- //
- // Save the negative number.
- //
- EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;
- } else {
- EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
- }
- } else {
- if (HexInput) {
- EditValue = Digital;
- } else if (IntInput && Negative) {
- //
- // Save the negative number.
- //
- EditValue = ~(Key.UnicodeChar - L'0') + 1;
- } else {
- EditValue = Key.UnicodeChar - L'0';
- }
- }
-
- if (IntInput) {
- ValidateFail = FALSE;
- //
- // When user input a new value, should check the current value.
- // If user input a negative value, should compare it with minimum
- // value, else compare it with maximum value.
- //
- if (Negative) {
- ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
- } else {
- ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
- }
-
- if (ValidateFail) {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- ASSERT (Count < ARRAY_SIZE (PreviousNumber));
- EditValue = PreviousNumber[Count];
- break;
- }
- } else {
- if (EditValue > Maximum) {
- UpdateStatusBar (INPUT_ERROR, TRUE);
- ASSERT (Count < ARRAY_SIZE (PreviousNumber));
- EditValue = PreviousNumber[Count];
- break;
- }
- }
-
- UpdateStatusBar (INPUT_ERROR, FALSE);
-
- Count++;
- ASSERT (Count < (ARRAY_SIZE (PreviousNumber)));
- PreviousNumber[Count] = EditValue;
-
- gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
- PrintCharAt (Column, Row, Key.UnicodeChar);
- Column++;
- }
-
- break;
- }
- } while (TRUE);
-}
-
-/**
- Adjust option order base on the question value.
-
- @param Question Pointer to current question.
- @param PopUpMenuLines The line number of the pop up menu.
-
- @retval EFI_SUCCESS If Option input is processed successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-AdjustOptionOrder (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
- OUT UINTN *PopUpMenuLines
- )
-{
- UINTN Index;
- EFI_IFR_ORDERED_LIST *OrderList;
- UINT8 *ValueArray;
- UINT8 ValueType;
- LIST_ENTRY *Link;
- DISPLAY_QUESTION_OPTION *OneOfOption;
- EFI_HII_VALUE *HiiValueArray;
-
- Link = GetFirstNode (&Question->OptionListHead);
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- ValueArray = Question->CurrentValue.Buffer;
- ValueType = OneOfOption->OptionOpCode->Type;
- OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
-
- for (Index = 0; Index < OrderList->MaxContainers; Index++) {
- if (GetArrayData (ValueArray, ValueType, Index) == 0) {
- break;
- }
- }
-
- *PopUpMenuLines = Index;
-
- //
- // Prepare HiiValue array
- //
- HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));
- ASSERT (HiiValueArray != NULL);
-
- for (Index = 0; Index < *PopUpMenuLines; Index++) {
- HiiValueArray[Index].Type = ValueType;
- HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
- }
-
- for (Index = 0; Index < *PopUpMenuLines; Index++) {
- OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);
- if (OneOfOption == NULL) {
- return EFI_NOT_FOUND;
- }
-
- RemoveEntryList (&OneOfOption->Link);
-
- //
- // Insert to head.
- //
- InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
- }
-
- FreePool (HiiValueArray);
-
- return EFI_SUCCESS;
-}
-
-/**
- Base on the type to compare the value.
-
- @param Value1 The first value need to compare.
- @param Value2 The second value need to compare.
- @param Type The value type for above two values.
-
- @retval TRUE The two value are same.
- @retval FALSE The two value are different.
-
-**/
-BOOLEAN
-IsValuesEqual (
- IN EFI_IFR_TYPE_VALUE *Value1,
- IN EFI_IFR_TYPE_VALUE *Value2,
- IN UINT8 Type
- )
-{
- switch (Type) {
- case EFI_IFR_TYPE_BOOLEAN:
- case EFI_IFR_TYPE_NUM_SIZE_8:
- return (BOOLEAN)(Value1->u8 == Value2->u8);
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- return (BOOLEAN)(Value1->u16 == Value2->u16);
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- return (BOOLEAN)(Value1->u32 == Value2->u32);
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- return (BOOLEAN)(Value1->u64 == Value2->u64);
-
- default:
- ASSERT (FALSE);
- return FALSE;
- }
-}
-
-/**
- Base on the type to set the value.
-
- @param Dest The dest value.
- @param Source The source value.
- @param Type The value type for above two values.
-
-**/
-VOID
-SetValuesByType (
- OUT EFI_IFR_TYPE_VALUE *Dest,
- IN EFI_IFR_TYPE_VALUE *Source,
- IN UINT8 Type
- )
-{
- switch (Type) {
- case EFI_IFR_TYPE_BOOLEAN:
- Dest->b = Source->b;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_8:
- Dest->u8 = Source->u8;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- Dest->u16 = Source->u16;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- Dest->u32 = Source->u32;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- Dest->u64 = Source->u64;
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-}
-
-/**
- Get selection for OneOf and OrderedList (Left/Right will be ignored).
-
- @param MenuOption Pointer to the current input menu.
-
- @retval EFI_SUCCESS If Option input is processed successfully
- @retval EFI_DEVICE_ERROR If operation fails
-
-**/
-EFI_STATUS
-GetSelectionInputPopUp (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- EFI_INPUT_KEY Key;
- UINTN Index;
- CHAR16 *StringPtr;
- CHAR16 *TempStringPtr;
- UINTN Index2;
- UINTN TopOptionIndex;
- UINTN HighlightOptionIndex;
- UINTN Start;
- UINTN End;
- UINTN Top;
- UINTN Bottom;
- UINTN PopUpMenuLines;
- UINTN MenuLinesInView;
- UINTN PopUpWidth;
- CHAR16 Character;
- INT32 SavedAttribute;
- BOOLEAN ShowDownArrow;
- BOOLEAN ShowUpArrow;
- UINTN DimensionsWidth;
- LIST_ENTRY *Link;
- BOOLEAN OrderedList;
- UINT8 *ValueArray;
- UINT8 *ReturnValue;
- UINT8 ValueType;
- EFI_HII_VALUE HiiValue;
- DISPLAY_QUESTION_OPTION *OneOfOption;
- DISPLAY_QUESTION_OPTION *CurrentOption;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- INTN Result;
- EFI_IFR_ORDERED_LIST *OrderList;
-
- DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
-
- ValueArray = NULL;
- ValueType = 0;
- CurrentOption = NULL;
- ShowDownArrow = FALSE;
- ShowUpArrow = FALSE;
-
- ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));
-
- Question = MenuOption->ThisTag;
- if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
- Link = GetFirstNode (&Question->OptionListHead);
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- ValueArray = Question->CurrentValue.Buffer;
- ValueType = OneOfOption->OptionOpCode->Type;
- OrderedList = TRUE;
- OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
- } else {
- OrderedList = FALSE;
- OrderList = NULL;
- }
-
- //
- // Calculate Option count
- //
- PopUpMenuLines = 0;
- if (OrderedList) {
- AdjustOptionOrder (Question, &PopUpMenuLines);
- } else {
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- PopUpMenuLines++;
- Link = GetNextNode (&Question->OptionListHead, Link);
- }
- }
-
- //
- // Get the number of one of options present and its size
- //
- PopUpWidth = 0;
- HighlightOptionIndex = 0;
- Link = GetFirstNode (&Question->OptionListHead);
- for (Index = 0; Index < PopUpMenuLines; Index++) {
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
-
- StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
- if (StrLen (StringPtr) > PopUpWidth) {
- PopUpWidth = StrLen (StringPtr);
- }
-
- FreePool (StringPtr);
- HiiValue.Type = OneOfOption->OptionOpCode->Type;
- SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
- if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
- //
- // Find current selected Option for OneOf
- //
- HighlightOptionIndex = Index;
- }
-
- Link = GetNextNode (&Question->OptionListHead, Link);
- }
-
- //
- // Perform popup menu initialization.
- //
- PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
-
- SavedAttribute = gST->ConOut->Mode->Attribute;
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
-
- if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
- PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
- }
-
- Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
- End = Start + PopUpWidth + POPUP_FRAME_WIDTH;
- Top = gStatementDimensions.TopRow;
- Bottom = gStatementDimensions.BottomRow - 1;
-
- MenuLinesInView = Bottom - Top - 1;
- if (MenuLinesInView >= PopUpMenuLines) {
- Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
- Bottom = Top + PopUpMenuLines + 1;
- } else {
- ShowDownArrow = TRUE;
- }
-
- if (HighlightOptionIndex > (MenuLinesInView - 1)) {
- TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
- } else {
- TopOptionIndex = 0;
- }
-
- do {
- //
- // Clear that portion of the screen
- //
- ClearLines (Start, End, Top, Bottom, GetPopupColor ());
-
- //
- // Draw "One of" pop-up menu
- //
- Character = BOXDRAW_DOWN_RIGHT;
- PrintCharAt (Start, Top, Character);
- for (Index = Start; Index + 2 < End; Index++) {
- if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
- Character = GEOMETRICSHAPE_UP_TRIANGLE;
- } else {
- Character = BOXDRAW_HORIZONTAL;
- }
-
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- Character = BOXDRAW_VERTICAL;
- for (Index = Top + 1; Index < Bottom; Index++) {
- PrintCharAt (Start, Index, Character);
- PrintCharAt (End - 1, Index, Character);
- }
-
- //
- // Move to top Option
- //
- Link = GetFirstNode (&Question->OptionListHead);
- for (Index = 0; Index < TopOptionIndex; Index++) {
- Link = GetNextNode (&Question->OptionListHead, Link);
- }
-
- //
- // Display the One of options
- //
- Index2 = Top + 1;
- for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
- ASSERT (StringPtr != NULL);
- //
- // If the string occupies multiple lines, truncate it to fit in one line,
- // and append a "..." for indication.
- //
- if (StrLen (StringPtr) > (PopUpWidth - 1)) {
- TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
- ASSERT (TempStringPtr != NULL);
- CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
- FreePool (StringPtr);
- StringPtr = TempStringPtr;
- StrCatS (StringPtr, PopUpWidth - 1, L"...");
- }
-
- if (Index == HighlightOptionIndex) {
- //
- // Highlight the selected one
- //
- CurrentOption = OneOfOption;
-
- gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
- PrintStringAt (Start + 2, Index2, StringPtr);
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
- } else {
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
- PrintStringAt (Start + 2, Index2, StringPtr);
- }
-
- Index2++;
- FreePool (StringPtr);
- }
-
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (Start, Bottom, Character);
- for (Index = Start; Index + 2 < End; Index++) {
- if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
- Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
- } else {
- Character = BOXDRAW_HORIZONTAL;
- }
-
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_UP_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
-
- //
- // Get User selection
- //
- Key.UnicodeChar = CHAR_NULL;
- if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
- Key.ScanCode = gDirection;
- gDirection = 0;
- goto TheKey;
- }
-
- WaitForKeyStroke (&Key);
-
-TheKey:
- switch (Key.UnicodeChar) {
- case '+':
- if (OrderedList) {
- if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
- //
- // Highlight reaches the top of the popup window, scroll one menu item.
- //
- TopOptionIndex--;
- ShowDownArrow = TRUE;
- }
-
- if (TopOptionIndex == 0) {
- ShowUpArrow = FALSE;
- }
-
- if (HighlightOptionIndex > 0) {
- HighlightOptionIndex--;
-
- ASSERT (CurrentOption != NULL);
- SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
- }
- }
-
- break;
-
- case '-':
- //
- // If an ordered list op-code, we will allow for a popup of +/- keys
- // to create an ordered list of items
- //
- if (OrderedList) {
- if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
- (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
- {
- //
- // Highlight reaches the bottom of the popup window, scroll one menu item.
- //
- TopOptionIndex++;
- ShowUpArrow = TRUE;
- }
-
- if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
- ShowDownArrow = FALSE;
- }
-
- if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
- HighlightOptionIndex++;
-
- ASSERT (CurrentOption != NULL);
- SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
- }
- }
-
- break;
-
- case CHAR_NULL:
- switch (Key.ScanCode) {
- case SCAN_UP:
- case SCAN_DOWN:
- if (Key.ScanCode == SCAN_UP) {
- if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
- //
- // Highlight reaches the top of the popup window, scroll one menu item.
- //
- TopOptionIndex--;
- ShowDownArrow = TRUE;
- }
-
- if (TopOptionIndex == 0) {
- ShowUpArrow = FALSE;
- }
-
- if (HighlightOptionIndex > 0) {
- HighlightOptionIndex--;
- }
- } else {
- if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
- (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
- {
- //
- // Highlight reaches the bottom of the popup window, scroll one menu item.
- //
- TopOptionIndex++;
- ShowUpArrow = TRUE;
- }
-
- if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
- ShowDownArrow = FALSE;
- }
-
- if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
- HighlightOptionIndex++;
- }
- }
-
- break;
-
- case SCAN_ESC:
- gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
-
- //
- // Restore link list order for orderedlist
- //
- if (OrderedList) {
- HiiValue.Type = ValueType;
- HiiValue.Value.u64 = 0;
- for (Index = 0; Index < OrderList->MaxContainers; Index++) {
- HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
- if (HiiValue.Value.u64 == 0) {
- break;
- }
-
- OneOfOption = ValueToOption (Question, &HiiValue);
- if (OneOfOption == NULL) {
- return EFI_NOT_FOUND;
- }
-
- RemoveEntryList (&OneOfOption->Link);
- InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
- }
- }
-
- return EFI_DEVICE_ERROR;
-
- default:
- break;
- }
-
- break;
-
- case CHAR_CARRIAGE_RETURN:
- //
- // return the current selection
- //
- if (OrderedList) {
- ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
- ASSERT (ReturnValue != NULL);
- Index = 0;
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);
-
- Index++;
- if (Index > OrderList->MaxContainers) {
- break;
- }
- }
-
- if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
- FreePool (ReturnValue);
- return EFI_DEVICE_ERROR;
- } else {
- gUserInput->InputValue.Buffer = ReturnValue;
- gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
- }
- } else {
- ASSERT (CurrentOption != NULL);
- gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
- if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
- return EFI_DEVICE_ERROR;
- } else {
- SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
- }
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
-
- return EFI_SUCCESS;
-
- default:
- break;
- }
- } while (TRUE);
-}
+/** @file +Implementation for handling user input from the User Interfaces. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FormDisplay.h" + +/** + Get maximum and minimum info from this opcode. + + @param OpCode Pointer to the current input opcode. + @param Minimum The minimum size info for this opcode. + @param Maximum The maximum size info for this opcode. + +**/ +VOID +GetFieldFromOp ( + IN EFI_IFR_OP_HEADER *OpCode, + OUT UINTN *Minimum, + OUT UINTN *Maximum + ) +{ + EFI_IFR_STRING *StringOp; + EFI_IFR_PASSWORD *PasswordOp; + + if (OpCode->OpCode == EFI_IFR_STRING_OP) { + StringOp = (EFI_IFR_STRING *)OpCode; + *Minimum = StringOp->MinSize; + *Maximum = StringOp->MaxSize; + } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) { + PasswordOp = (EFI_IFR_PASSWORD *)OpCode; + *Minimum = PasswordOp->MinSize; + *Maximum = PasswordOp->MaxSize; + } else { + *Minimum = 0; + *Maximum = 0; + } +} + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Old user input and destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + IN OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 NullCharacter; + UINTN ScreenSize; + CHAR16 Space[2]; + CHAR16 KeyPad[2]; + CHAR16 *TempString; + CHAR16 *BufferedString; + UINTN Index; + UINTN Index2; + UINTN Count; + UINTN Start; + UINTN Top; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + UINTN CurrentCursor; + BOOLEAN CursorVisible; + UINTN Minimum; + UINTN Maximum; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + BOOLEAN IsPassword; + UINTN MaxLen; + + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; + DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; + + NullCharacter = CHAR_NULL; + ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); + Space[0] = L' '; + Space[1] = CHAR_NULL; + + Question = MenuOption->ThisTag; + GetFieldFromOp (Question->OpCode, &Minimum, &Maximum); + + if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) { + IsPassword = TRUE; + } else { + IsPassword = FALSE; + } + + MaxLen = Maximum + 1; + TempString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (TempString); + + if (ScreenSize < (Maximum + 1)) { + ScreenSize = Maximum + 1; + } + + if ((ScreenSize + 2) > DimensionsWidth) { + ScreenSize = DimensionsWidth - 2; + } + + BufferedString = AllocateZeroPool (ScreenSize * 2); + ASSERT (BufferedString); + + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1; + + // + // Display prompt for string + // + // CreateDialog (NULL, "", Prompt, Space, "", NULL); + CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + + CursorVisible = gST->ConOut->Mode->CursorVisible; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + CurrentCursor = GetStringWidth (StringPtr) / 2 - 1; + if (CurrentCursor != 0) { + // + // Show the string which has beed saved before. + // + SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); + PrintStringAt (Start + 1, Top + 3, BufferedString); + + if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + if (IsPassword) { + gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + + if (IsPassword) { + PrintCharAt ((UINTN)-1, (UINTN)-1, L'*'); + } + } + + if (!IsPassword) { + PrintStringAt (Start + 1, Top + 3, BufferedString); + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); + } + + do { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + if (CurrentCursor > 0) { + CurrentCursor--; + } + + break; + + case SCAN_RIGHT: + if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) { + CurrentCursor++; + } + + break; + + case SCAN_ESC: + FreePool (TempString); + FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + + case SCAN_DELETE: + for (Index = CurrentCursor; StringPtr[Index] != CHAR_NULL; Index++) { + StringPtr[Index] = StringPtr[Index + 1]; + PrintCharAt (Start + Index + 1, Top + 3, IsPassword && StringPtr[Index] != CHAR_NULL ? L'*' : StringPtr[Index]); + } + + break; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) { + FreePool (TempString); + FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_SUCCESS; + } else { + // + // Simply create a popup to tell the user that they had typed in too few characters. + // To save code space, we can then treat this as an error and return back to the menu. + // + do { + CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + FreePool (TempString); + FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + } + + case CHAR_BACKSPACE: + if ((StringPtr[0] != CHAR_NULL) && (CurrentCursor != 0)) { + for (Index = 0; Index < CurrentCursor - 1; Index++) { + TempString[Index] = StringPtr[Index]; + } + + Count = GetStringWidth (StringPtr) / 2 - 1; + if (Count >= CurrentCursor) { + for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) { + TempString[Index] = StringPtr[Index2]; + } + + TempString[Index] = CHAR_NULL; + } + + // + // Effectively truncate string by 1 character + // + StrCpyS (StringPtr, MaxLen, TempString); + CurrentCursor--; + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpyS (StringPtr, MaxLen, &Key.UnicodeChar, 1); + CurrentCursor++; + } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + Count = GetStringWidth (StringPtr) / 2 - 1; + if (CurrentCursor < Count) { + for (Index = 0; Index < CurrentCursor; Index++) { + TempString[Index] = StringPtr[Index]; + } + + TempString[Index] = CHAR_NULL; + StrCatS (TempString, MaxLen, KeyPad); + StrCatS (TempString, MaxLen, StringPtr + CurrentCursor); + StrCpyS (StringPtr, MaxLen, TempString); + } else { + StrCatS (StringPtr, MaxLen, KeyPad); + } + + CurrentCursor++; + } + + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); + PrintStringAt (Start + 1, Top + 3, BufferedString); + + if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + if (IsPassword) { + gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + + if (IsPassword) { + PrintCharAt ((UINTN)-1, (UINTN)-1, L'*'); + } + } + + if (!IsPassword) { + PrintStringAt (Start + 1, Top + 3, BufferedString); + } + + break; + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3); + } while (TRUE); +} + +/** + Adjust the value to the correct one. Rules follow the sample: + like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01 + Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28 + + @param QuestionValue Pointer to current question. + @param Sequence The sequence of the field in the question. +**/ +VOID +AdjustQuestionValue ( + IN EFI_HII_VALUE *QuestionValue, + IN UINT8 Sequence + ) +{ + UINT8 Month; + UINT16 Year; + UINT8 Maximum; + UINT8 Minimum; + + Month = QuestionValue->Value.date.Month; + Year = QuestionValue->Value.date.Year; + Minimum = 1; + + switch (Month) { + case 2: + if (((Year % 4) == 0) && (((Year % 100) != 0) || ((Year % 400) == 0))) { + Maximum = 29; + } else { + Maximum = 28; + } + + break; + case 4: + case 6: + case 9: + case 11: + Maximum = 30; + break; + default: + Maximum = 31; + break; + } + + // + // Change the month area. + // + if (Sequence == 0) { + if (QuestionValue->Value.date.Day > Maximum) { + QuestionValue->Value.date.Day = Maximum; + } + } + + // + // Change the Year area. + // + if (Sequence == 2) { + if (QuestionValue->Value.date.Day > Maximum) { + QuestionValue->Value.date.Day = Minimum; + } + } +} + +/** + Get field info from numeric opcode. + + @param OpCode Pointer to the current input opcode. + @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type. + @param QuestionValue Input question value, with EFI_HII_VALUE type. + @param Value Return question value, always return UINT64 type. + @param Minimum The minimum size info for this opcode. + @param Maximum The maximum size info for this opcode. + @param Step The step size info for this opcode. + @param StorageWidth The storage width info for this opcode. + +**/ +VOID +GetValueFromNum ( + IN EFI_IFR_OP_HEADER *OpCode, + IN BOOLEAN IntInput, + IN EFI_HII_VALUE *QuestionValue, + OUT UINT64 *Value, + OUT UINT64 *Minimum, + OUT UINT64 *Maximum, + OUT UINT64 *Step, + OUT UINT16 *StorageWidth + ) +{ + EFI_IFR_NUMERIC *NumericOp; + + NumericOp = (EFI_IFR_NUMERIC *)OpCode; + + switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + if (IntInput) { + *Minimum = (INT64)(INT8)NumericOp->data.u8.MinValue; + *Maximum = (INT64)(INT8)NumericOp->data.u8.MaxValue; + *Value = (INT64)(INT8)QuestionValue->Value.u8; + } else { + *Minimum = NumericOp->data.u8.MinValue; + *Maximum = NumericOp->data.u8.MaxValue; + *Value = QuestionValue->Value.u8; + } + + *Step = NumericOp->data.u8.Step; + *StorageWidth = (UINT16)sizeof (UINT8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + if (IntInput) { + *Minimum = (INT64)(INT16)NumericOp->data.u16.MinValue; + *Maximum = (INT64)(INT16)NumericOp->data.u16.MaxValue; + *Value = (INT64)(INT16)QuestionValue->Value.u16; + } else { + *Minimum = NumericOp->data.u16.MinValue; + *Maximum = NumericOp->data.u16.MaxValue; + *Value = QuestionValue->Value.u16; + } + + *Step = NumericOp->data.u16.Step; + *StorageWidth = (UINT16)sizeof (UINT16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + if (IntInput) { + *Minimum = (INT64)(INT32)NumericOp->data.u32.MinValue; + *Maximum = (INT64)(INT32)NumericOp->data.u32.MaxValue; + *Value = (INT64)(INT32)QuestionValue->Value.u32; + } else { + *Minimum = NumericOp->data.u32.MinValue; + *Maximum = NumericOp->data.u32.MaxValue; + *Value = QuestionValue->Value.u32; + } + + *Step = NumericOp->data.u32.Step; + *StorageWidth = (UINT16)sizeof (UINT32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + if (IntInput) { + *Minimum = (INT64)NumericOp->data.u64.MinValue; + *Maximum = (INT64)NumericOp->data.u64.MaxValue; + *Value = (INT64)QuestionValue->Value.u64; + } else { + *Minimum = NumericOp->data.u64.MinValue; + *Maximum = NumericOp->data.u64.MaxValue; + *Value = QuestionValue->Value.u64; + } + + *Step = NumericOp->data.u64.Step; + *StorageWidth = (UINT16)sizeof (UINT64); + break; + + default: + break; + } + + if (*Maximum == 0) { + *Maximum = (UINT64)-1; + } +} + +/** + This routine reads a numeric value from the user input. + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_OPTION *MenuOption + ) +{ + UINTN Column; + UINTN Row; + CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH]; + CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1]; + UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3]; + UINTN Count; + UINTN Loop; + BOOLEAN ManualInput; + BOOLEAN HexInput; + BOOLEAN IntInput; + BOOLEAN Negative; + BOOLEAN ValidateFail; + BOOLEAN DateOrTime; + UINTN InputWidth; + UINT64 EditValue; + UINT64 Step; + UINT64 Minimum; + UINT64 Maximum; + UINTN EraseLen; + UINT8 Digital; + EFI_INPUT_KEY Key; + EFI_HII_VALUE *QuestionValue; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + EFI_IFR_NUMERIC *NumericOp; + UINT16 StorageWidth; + + Column = MenuOption->OptCol; + Row = MenuOption->Row; + PreviousNumber[0] = 0; + Count = 0; + InputWidth = 0; + Digital = 0; + StorageWidth = 0; + Minimum = 0; + Maximum = 0; + NumericOp = NULL; + IntInput = FALSE; + HexInput = FALSE; + Negative = FALSE; + ValidateFail = FALSE; + + Question = MenuOption->ThisTag; + QuestionValue = &Question->CurrentValue; + ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16)); + + // + // Only two case, user can enter to this function: Enter and +/- case. + // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT + // + ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE); + + if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) { + DateOrTime = TRUE; + } else { + DateOrTime = FALSE; + } + + // + // Prepare Value to be edit + // + EraseLen = 0; + EditValue = 0; + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { + Step = 1; + Minimum = 1; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 12; + EraseLen = 4; + EditValue = QuestionValue->Value.date.Month; + break; + + case 1: + switch (QuestionValue->Value.date.Month) { + case 2: + if (((QuestionValue->Value.date.Year % 4) == 0) && + (((QuestionValue->Value.date.Year % 100) != 0) || + ((QuestionValue->Value.date.Year % 400) == 0))) + { + Maximum = 29; + } else { + Maximum = 28; + } + + break; + case 4: + case 6: + case 9: + case 11: + Maximum = 30; + break; + default: + Maximum = 31; + break; + } + + EraseLen = 3; + EditValue = QuestionValue->Value.date.Day; + break; + + case 2: + Maximum = 0xffff; + EraseLen = 5; + EditValue = QuestionValue->Value.date.Year; + break; + + default: + break; + } + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { + Step = 1; + Minimum = 0; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 23; + EraseLen = 4; + EditValue = QuestionValue->Value.time.Hour; + break; + + case 1: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Minute; + break; + + case 2: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Second; + break; + + default: + break; + } + } else { + ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP); + NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode; + GetValueFromNum (Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth); + EraseLen = gOptionBlockWidth; + } + + if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) { + if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX) { + HexInput = TRUE; + } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0) { + // + // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number. + // + IntInput = TRUE; + } + } + + // + // Enter from "Enter" input, clear the old word showing. + // + if (ManualInput) { + if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) { + if (HexInput) { + InputWidth = StorageWidth * 2; + } else { + switch (StorageWidth) { + case 1: + InputWidth = 3; + break; + + case 2: + InputWidth = 5; + break; + + case 4: + InputWidth = 10; + break; + + case 8: + InputWidth = 20; + break; + + default: + InputWidth = 0; + break; + } + + if (IntInput) { + // + // Support an extra '-' for negative number. + // + InputWidth += 1; + } + } + + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH); + InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 2] = L'\0'; + + PrintStringAt (Column, Row, InputText); + Column++; + } + + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { + if (MenuOption->Sequence == 2) { + InputWidth = 4; + } else { + InputWidth = 2; + } + + if (MenuOption->Sequence == 0) { + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + InputText[InputWidth + 1] = DATE_SEPARATOR; + InputText[InputWidth + 2] = L'\0'; + } else if (MenuOption->Sequence == 1) { + SetUnicodeMem (InputText, InputWidth, L' '); + InputText[InputWidth] = DATE_SEPARATOR; + InputText[InputWidth + 1] = L'\0'; + } else { + SetUnicodeMem (InputText, InputWidth, L' '); + InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 1] = L'\0'; + } + + PrintStringAt (Column, Row, InputText); + if (MenuOption->Sequence == 0) { + Column++; + } + } + + if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { + InputWidth = 2; + + if (MenuOption->Sequence == 0) { + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + InputText[InputWidth + 1] = TIME_SEPARATOR; + InputText[InputWidth + 2] = L'\0'; + } else if (MenuOption->Sequence == 1) { + SetUnicodeMem (InputText, InputWidth, L' '); + InputText[InputWidth] = TIME_SEPARATOR; + InputText[InputWidth + 1] = L'\0'; + } else { + SetUnicodeMem (InputText, InputWidth, L' '); + InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 1] = L'\0'; + } + + PrintStringAt (Column, Row, InputText); + if (MenuOption->Sequence == 0) { + Column++; + } + } + } + + // + // First time we enter this handler, we need to check to see if + // we were passed an increment or decrement directive + // + do { + Key.UnicodeChar = CHAR_NULL; + if (gDirection != 0) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey2; + } + + WaitForKeyStroke (&Key); + +TheKey2: + switch (Key.UnicodeChar) { + case '+': + case '-': + if (ManualInput && IntInput) { + // + // In Manual input mode, check whether input the negative flag. + // + if (Key.UnicodeChar == '-') { + if (Negative) { + break; + } + + Negative = TRUE; + PrintCharAt (Column++, Row, Key.UnicodeChar); + } + } else { + if (Key.UnicodeChar == '+') { + Key.ScanCode = SCAN_RIGHT; + } else { + Key.ScanCode = SCAN_LEFT; + } + + Key.UnicodeChar = CHAR_NULL; + goto TheKey2; + } + + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_RIGHT: + if (DateOrTime && !ManualInput) { + // + // By setting this value, we will return back to the caller. + // We need to do this since an auto-refresh will destroy the adjustment + // based on what the real-time-clock is showing. So we always commit + // upon changing the value. + // + gDirection = SCAN_DOWN; + } + + if ((Step != 0) && !ManualInput) { + if (Key.ScanCode == SCAN_LEFT) { + if (IntInput) { + if ((INT64)EditValue >= (INT64)Minimum + (INT64)Step) { + EditValue = EditValue - Step; + } else if ((INT64)EditValue > (INT64)Minimum) { + EditValue = Minimum; + } else { + EditValue = Maximum; + } + } else { + if (EditValue >= Minimum + Step) { + EditValue = EditValue - Step; + } else if (EditValue > Minimum) { + EditValue = Minimum; + } else { + EditValue = Maximum; + } + } + } else if (Key.ScanCode == SCAN_RIGHT) { + if (IntInput) { + if ((INT64)EditValue + (INT64)Step <= (INT64)Maximum) { + EditValue = EditValue + Step; + } else if ((INT64)EditValue < (INT64)Maximum) { + EditValue = Maximum; + } else { + EditValue = Minimum; + } + } else { + if (EditValue + Step <= Maximum) { + EditValue = EditValue + Step; + } else if (EditValue < Maximum) { + EditValue = Maximum; + } else { + EditValue = Minimum; + } + } + } + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { + if (MenuOption->Sequence == 2) { + // + // Year + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16)EditValue); + } else { + // + // Month/Day + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue); + } + + if (MenuOption->Sequence == 0) { + ASSERT (EraseLen >= 2); + FormattedNumber[EraseLen - 2] = DATE_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + ASSERT (EraseLen >= 1); + FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; + } + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue); + + if (MenuOption->Sequence == 0) { + ASSERT (EraseLen >= 2); + FormattedNumber[EraseLen - 2] = TIME_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + ASSERT (EraseLen >= 1); + FormattedNumber[EraseLen - 1] = TIME_SEPARATOR; + } + } else { + QuestionValue->Value.u64 = EditValue; + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + } + + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); + for (Loop = 0; Loop < EraseLen; Loop++) { + PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); + } + + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); + + if (MenuOption->Sequence == 0) { + PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); + Column = MenuOption->OptCol + 1; + } + + PrintStringAt (Column, Row, FormattedNumber); + + if (!DateOrTime || (MenuOption->Sequence == 2)) { + PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER); + } + } + + goto EnterCarriageReturn; + + case SCAN_UP: + case SCAN_DOWN: + goto EnterCarriageReturn; + + case SCAN_ESC: + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + +EnterCarriageReturn: + + case CHAR_CARRIAGE_RETURN: + // + // Validate input value with Minimum value. + // + ValidateFail = FALSE; + if (IntInput) { + // + // After user input Enter, need to check whether the input value. + // If input a negative value, should compare with maximum value. + // else compare with the minimum value. + // + if (Negative) { + ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE; + } else { + ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE; + } + + if (ValidateFail) { + UpdateStatusBar (INPUT_ERROR, TRUE); + break; + } + } else if (EditValue < Minimum) { + UpdateStatusBar (INPUT_ERROR, TRUE); + break; + } + + UpdateStatusBar (INPUT_ERROR, FALSE); + CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE)); + QuestionValue = &gUserInput->InputValue; + // + // Store Edit value back to Question + // + if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.date.Month = (UINT8)EditValue; + break; + + case 1: + QuestionValue->Value.date.Day = (UINT8)EditValue; + break; + + case 2: + QuestionValue->Value.date.Year = (UINT16)EditValue; + break; + + default: + break; + } + } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.time.Hour = (UINT8)EditValue; + break; + + case 1: + QuestionValue->Value.time.Minute = (UINT8)EditValue; + break; + + case 2: + QuestionValue->Value.time.Second = (UINT8)EditValue; + break; + + default: + break; + } + } else { + // + // Numeric + // + QuestionValue->Value.u64 = EditValue; + } + + // + // Adjust the value to the correct one. + // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01 + // 2013.03.29 -> 2013.02.29 -> 2013.02.28 + // + if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) && + ((MenuOption->Sequence == 0) || (MenuOption->Sequence == 2))) + { + AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence); + } + + return EFI_SUCCESS; + + case CHAR_BACKSPACE: + if (ManualInput) { + if (Count == 0) { + if (Negative) { + Negative = FALSE; + Column--; + PrintStringAt (Column, Row, L" "); + } + + break; + } + + // + // Remove a character + // + EditValue = PreviousNumber[Count - 1]; + UpdateStatusBar (INPUT_ERROR, FALSE); + Count--; + Column--; + PrintStringAt (Column, Row, L" "); + } + + break; + + default: + if (ManualInput) { + if (HexInput) { + if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) { + Digital = (UINT8)(Key.UnicodeChar - L'0'); + } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) { + Digital = (UINT8)(Key.UnicodeChar - L'A' + 0x0A); + } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) { + Digital = (UINT8)(Key.UnicodeChar - L'a' + 0x0A); + } else { + UpdateStatusBar (INPUT_ERROR, TRUE); + break; + } + } else { + if ((Key.UnicodeChar > L'9') || (Key.UnicodeChar < L'0')) { + UpdateStatusBar (INPUT_ERROR, TRUE); + break; + } + } + + // + // If Count exceed input width, there is no way more is valid + // + if (Count >= InputWidth) { + break; + } + + // + // Someone typed something valid! + // + if (Count != 0) { + if (HexInput) { + EditValue = LShiftU64 (EditValue, 4) + Digital; + } else if (IntInput && Negative) { + // + // Save the negative number. + // + EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1; + } else { + EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0'); + } + } else { + if (HexInput) { + EditValue = Digital; + } else if (IntInput && Negative) { + // + // Save the negative number. + // + EditValue = ~(Key.UnicodeChar - L'0') + 1; + } else { + EditValue = Key.UnicodeChar - L'0'; + } + } + + if (IntInput) { + ValidateFail = FALSE; + // + // When user input a new value, should check the current value. + // If user input a negative value, should compare it with minimum + // value, else compare it with maximum value. + // + if (Negative) { + ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE; + } else { + ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE; + } + + if (ValidateFail) { + UpdateStatusBar (INPUT_ERROR, TRUE); + ASSERT (Count < ARRAY_SIZE (PreviousNumber)); + EditValue = PreviousNumber[Count]; + break; + } + } else { + if (EditValue > Maximum) { + UpdateStatusBar (INPUT_ERROR, TRUE); + ASSERT (Count < ARRAY_SIZE (PreviousNumber)); + EditValue = PreviousNumber[Count]; + break; + } + } + + UpdateStatusBar (INPUT_ERROR, FALSE); + + Count++; + ASSERT (Count < (ARRAY_SIZE (PreviousNumber))); + PreviousNumber[Count] = EditValue; + + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); + PrintCharAt (Column, Row, Key.UnicodeChar); + Column++; + } + + break; + } + } while (TRUE); +} + +/** + Adjust option order base on the question value. + + @param Question Pointer to current question. + @param PopUpMenuLines The line number of the pop up menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +AdjustOptionOrder ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + OUT UINTN *PopUpMenuLines + ) +{ + UINTN Index; + EFI_IFR_ORDERED_LIST *OrderList; + UINT8 *ValueArray; + UINT8 ValueType; + LIST_ENTRY *Link; + DISPLAY_QUESTION_OPTION *OneOfOption; + EFI_HII_VALUE *HiiValueArray; + + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + ValueArray = Question->CurrentValue.Buffer; + ValueType = OneOfOption->OptionOpCode->Type; + OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; + + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + if (GetArrayData (ValueArray, ValueType, Index) == 0) { + break; + } + } + + *PopUpMenuLines = Index; + + // + // Prepare HiiValue array + // + HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE)); + ASSERT (HiiValueArray != NULL); + + for (Index = 0; Index < *PopUpMenuLines; Index++) { + HiiValueArray[Index].Type = ValueType; + HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index); + } + + for (Index = 0; Index < *PopUpMenuLines; Index++) { + OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + + // + // Insert to head. + // + InsertHeadList (&Question->OptionListHead, &OneOfOption->Link); + } + + FreePool (HiiValueArray); + + return EFI_SUCCESS; +} + +/** + Base on the type to compare the value. + + @param Value1 The first value need to compare. + @param Value2 The second value need to compare. + @param Type The value type for above two values. + + @retval TRUE The two value are same. + @retval FALSE The two value are different. + +**/ +BOOLEAN +IsValuesEqual ( + IN EFI_IFR_TYPE_VALUE *Value1, + IN EFI_IFR_TYPE_VALUE *Value2, + IN UINT8 Type + ) +{ + switch (Type) { + case EFI_IFR_TYPE_BOOLEAN: + case EFI_IFR_TYPE_NUM_SIZE_8: + return (BOOLEAN)(Value1->u8 == Value2->u8); + + case EFI_IFR_TYPE_NUM_SIZE_16: + return (BOOLEAN)(Value1->u16 == Value2->u16); + + case EFI_IFR_TYPE_NUM_SIZE_32: + return (BOOLEAN)(Value1->u32 == Value2->u32); + + case EFI_IFR_TYPE_NUM_SIZE_64: + return (BOOLEAN)(Value1->u64 == Value2->u64); + + default: + ASSERT (FALSE); + return FALSE; + } +} + +/** + Base on the type to set the value. + + @param Dest The dest value. + @param Source The source value. + @param Type The value type for above two values. + +**/ +VOID +SetValuesByType ( + OUT EFI_IFR_TYPE_VALUE *Dest, + IN EFI_IFR_TYPE_VALUE *Source, + IN UINT8 Type + ) +{ + switch (Type) { + case EFI_IFR_TYPE_BOOLEAN: + Dest->b = Source->b; + break; + + case EFI_IFR_TYPE_NUM_SIZE_8: + Dest->u8 = Source->u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Dest->u16 = Source->u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Dest->u32 = Source->u32; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Dest->u64 = Source->u64; + break; + + default: + ASSERT (FALSE); + break; + } +} + +/** + Get selection for OneOf and OrderedList (Left/Right will be ignored). + + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_INPUT_KEY Key; + UINTN Index; + CHAR16 *StringPtr; + CHAR16 *TempStringPtr; + UINTN Index2; + UINTN TopOptionIndex; + UINTN HighlightOptionIndex; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + UINTN PopUpMenuLines; + UINTN MenuLinesInView; + UINTN PopUpWidth; + CHAR16 Character; + INT32 SavedAttribute; + BOOLEAN ShowDownArrow; + BOOLEAN ShowUpArrow; + UINTN DimensionsWidth; + LIST_ENTRY *Link; + BOOLEAN OrderedList; + UINT8 *ValueArray; + UINT8 *ReturnValue; + UINT8 ValueType; + EFI_HII_VALUE HiiValue; + DISPLAY_QUESTION_OPTION *OneOfOption; + DISPLAY_QUESTION_OPTION *CurrentOption; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + INTN Result; + EFI_IFR_ORDERED_LIST *OrderList; + + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; + + ValueArray = NULL; + ValueType = 0; + CurrentOption = NULL; + ShowDownArrow = FALSE; + ShowUpArrow = FALSE; + + ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE)); + + Question = MenuOption->ThisTag; + if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) { + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + ValueArray = Question->CurrentValue.Buffer; + ValueType = OneOfOption->OptionOpCode->Type; + OrderedList = TRUE; + OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; + } else { + OrderedList = FALSE; + OrderList = NULL; + } + + // + // Calculate Option count + // + PopUpMenuLines = 0; + if (OrderedList) { + AdjustOptionOrder (Question, &PopUpMenuLines); + } else { + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + PopUpMenuLines++; + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + // + // Get the number of one of options present and its size + // + PopUpWidth = 0; + HighlightOptionIndex = 0; + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < PopUpMenuLines; Index++) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + if (StrLen (StringPtr) > PopUpWidth) { + PopUpWidth = StrLen (StringPtr); + } + + FreePool (StringPtr); + HiiValue.Type = OneOfOption->OptionOpCode->Type; + SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type); + if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + // + // Find current selected Option for OneOf + // + HighlightOptionIndex = Index; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Perform popup menu initialization. + // + PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT; + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + + if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) { + PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH; + } + + Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn; + End = Start + PopUpWidth + POPUP_FRAME_WIDTH; + Top = gStatementDimensions.TopRow; + Bottom = gStatementDimensions.BottomRow - 1; + + MenuLinesInView = Bottom - Top - 1; + if (MenuLinesInView >= PopUpMenuLines) { + Top = Top + (MenuLinesInView - PopUpMenuLines) / 2; + Bottom = Top + PopUpMenuLines + 1; + } else { + ShowDownArrow = TRUE; + } + + if (HighlightOptionIndex > (MenuLinesInView - 1)) { + TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1; + } else { + TopOptionIndex = 0; + } + + do { + // + // Clear that portion of the screen + // + ClearLines (Start, End, Top, Bottom, GetPopupColor ()); + + // + // Draw "One of" pop-up menu + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_UP_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top + 1; Index < Bottom; Index++) { + PrintCharAt (Start, Index, Character); + PrintCharAt (End - 1, Index, Character); + } + + // + // Move to top Option + // + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < TopOptionIndex; Index++) { + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Display the One of options + // + Index2 = Top + 1; + for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + // + // If the string occupies multiple lines, truncate it to fit in one line, + // and append a "..." for indication. + // + if (StrLen (StringPtr) > (PopUpWidth - 1)) { + TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1)); + ASSERT (TempStringPtr != NULL); + CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5))); + FreePool (StringPtr); + StringPtr = TempStringPtr; + StrCatS (StringPtr, PopUpWidth - 1, L"..."); + } + + if (Index == HighlightOptionIndex) { + // + // Highlight the selected one + // + CurrentOption = OneOfOption; + + gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ()); + PrintStringAt (Start + 2, Index2, StringPtr); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + } else { + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + PrintStringAt (Start + 2, Index2, StringPtr); + } + + Index2++; + FreePool (StringPtr); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_DOWN_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + + // + // Get User selection + // + Key.UnicodeChar = CHAR_NULL; + if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey; + } + + WaitForKeyStroke (&Key); + +TheKey: + switch (Key.UnicodeChar) { + case '+': + if (OrderedList) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + + ASSERT (CurrentOption != NULL); + SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link); + } + } + + break; + + case '-': + // + // If an ordered list op-code, we will allow for a popup of +/- keys + // to create an ordered list of items + // + if (OrderedList) { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) + { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + + ASSERT (CurrentOption != NULL); + SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink); + } + } + + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_UP: + case SCAN_DOWN: + if (Key.ScanCode == SCAN_UP) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + } + } else { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) + { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + } + } + + break; + + case SCAN_ESC: + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + + // + // Restore link list order for orderedlist + // + if (OrderedList) { + HiiValue.Type = ValueType; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); + if (HiiValue.Value.u64 == 0) { + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } + } + + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + // + // return the current selection + // + if (OrderedList) { + ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen); + ASSERT (ReturnValue != NULL); + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64); + + Index++; + if (Index > OrderList->MaxContainers) { + break; + } + } + + if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) { + FreePool (ReturnValue); + return EFI_DEVICE_ERROR; + } else { + gUserInput->InputValue.Buffer = ReturnValue; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + } + } else { + ASSERT (CurrentOption != NULL); + gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type; + if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) { + return EFI_DEVICE_ERROR; + } else { + SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type); + } + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + + return EFI_SUCCESS; + + default: + break; + } + } while (TRUE); +} diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c b/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c index 9954c4e4d5..4f09ea7484 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c +++ b/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c @@ -1,750 +1,750 @@ -/** @file
-Implementation for Hii Popup Protocol.
-
-Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FormDisplay.h"
-
-EFI_SCREEN_DESCRIPTOR gPopupDimensions;
-LIST_ENTRY gUserSelectableOptions;
-EFI_STRING gMessageString;
-UINTN gMesStrLineNum;
-UINTN gMaxRowWidth;
-
-/**
- Free the user selectable option structure data.
-
- @param OptionList Point to the selectable option list which need to be freed.
-
-**/
-VOID
-FreeSelectableOptions (
- LIST_ENTRY *OptionList
- )
-{
- LIST_ENTRY *Link;
- USER_SELECTABLE_OPTION *SelectableOption;
-
- while (!IsListEmpty (OptionList)) {
- Link = GetFirstNode (OptionList);
- SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);
- RemoveEntryList (&SelectableOption->Link);
- FreePool (SelectableOption);
- }
-}
-
-/**
- Display one selectable option.
-
- @param SelectableOption The selectable option need to be drew.
- @param Highlight Whether the option need to be highlighted.
-
-**/
-VOID
-DisplayOneSelectableOption (
- IN USER_SELECTABLE_OPTION *SelectableOption,
- IN BOOLEAN Highlight
- )
-{
- if (Highlight) {
- gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
- }
-
- PrintStringAt (SelectableOption->OptionCol, SelectableOption->OptionRow, SelectableOption->OptionString);
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
-}
-
-/**
- Add one selectable option to option list. This is the work function for AddUserSelectableOptions.
-
- @param PopupType The option need to be drew.
- @param OptionType The type of this selection option.
- @param OptionString Point to the option string that to be shown.
- @param OptionCol The column that the option need to be drew at.
- @param OptionRow The row that the option need to be drew at.
-
- @retval EFI_SUCCESS This function implement successfully.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available.
-
-**/
-EFI_STATUS
-AddOneSelectableOption (
- IN EFI_HII_POPUP_TYPE PopupType,
- IN EFI_HII_POPUP_SELECTION OptionType,
- IN CHAR16 *OptionString,
- IN UINTN OptionCol,
- IN UINTN OptionRow
- )
-{
- USER_SELECTABLE_OPTION *UserSelectableOption;
-
- UserSelectableOption = AllocateZeroPool (sizeof (USER_SELECTABLE_OPTION));
- if (UserSelectableOption == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Initialize the user selectable option based on the PopupType and OptionType.
- // And then add the option to the option list gUserSelectableOptions.
- //
- UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE;
- UserSelectableOption->OptionString = OptionString;
- UserSelectableOption->OptionType = OptionType;
- UserSelectableOption->OptionCol = OptionCol;
- UserSelectableOption->OptionRow = OptionRow;
- UserSelectableOption->MinSequence = 0;
-
- switch (PopupType) {
- case EfiHiiPopupTypeOk:
- UserSelectableOption->MaxSequence = 0;
- UserSelectableOption->Sequence = 0;
- break;
- case EfiHiiPopupTypeOkCancel:
- UserSelectableOption->MaxSequence = 1;
- if (OptionType == EfiHiiPopupSelectionOk) {
- UserSelectableOption->Sequence = 0;
- } else {
- UserSelectableOption->Sequence = 1;
- }
-
- break;
- case EfiHiiPopupTypeYesNo:
- UserSelectableOption->MaxSequence = 1;
- if (OptionType == EfiHiiPopupSelectionYes) {
- UserSelectableOption->Sequence = 0;
- } else {
- UserSelectableOption->Sequence = 1;
- }
-
- break;
- case EfiHiiPopupTypeYesNoCancel:
- UserSelectableOption->MaxSequence = 2;
- if (OptionType == EfiHiiPopupSelectionYes) {
- UserSelectableOption->Sequence = 0;
- } else if (OptionType == EfiHiiPopupSelectionNo) {
- UserSelectableOption->Sequence = 1;
- } else {
- UserSelectableOption->Sequence = 2;
- }
-
- break;
- default:
- break;
- }
-
- InsertTailList (&gUserSelectableOptions, &UserSelectableOption->Link);
-
- return EFI_SUCCESS;
-}
-
-/**
- Add user selectable options to option list for different types of Popup.
-
- @param PopupType Type of the popup to display.
-
- @retval EFI_SUCCESS This function implement successfully.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available.
-
-**/
-EFI_STATUS
-AddUserSelectableOptions (
- IN EFI_HII_POPUP_TYPE PopupType
- )
-{
- EFI_STATUS Status;
- UINTN EndCol;
- UINTN StartCol;
- UINTN OptionCol;
- UINTN OptionRow;
- UINTN ColDimension;
-
- Status = EFI_SUCCESS;
- EndCol = gPopupDimensions.RightColumn;
- StartCol = gPopupDimensions.LeftColumn;
- OptionRow = gPopupDimensions.BottomRow - POPUP_BORDER;
- ColDimension = EndCol - StartCol + 1;
-
- InitializeListHead (&gUserSelectableOptions);
-
- switch (PopupType) {
- case EfiHiiPopupTypeOk:
- //
- // Add [Ok] option to the option list.
- //
- OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_WIDTH) / 2;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);
- break;
- case EfiHiiPopupTypeOkCancel:
- //
- // Add [Ok] and [Cancel] options to the option list.
- //
- OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);
- OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3 - (GetStringWidth (gCancelOption) -2) / 2 + 1;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);
- break;
- case EfiHiiPopupTypeYesNo:
- //
- // Add [Yes] and [No] options to the option list.
- //
- OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);
- OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3 - (GetStringWidth (gNoOption)- 2) / 2 + 1;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);
- break;
- case EfiHiiPopupTypeYesNoCancel:
- //
- // Add [Yes], [No] and [Cancel] options to the option list.
- //
- OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);
- OptionCol = StartCol + (ColDimension - (GetStringWidth (gNoOption) -2) / 2) / 2;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);
- OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4 - (GetStringWidth (gCancelOption) - 2) / 2 + 1;
- Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);
- break;
- default:
- break;
- }
-
- return Status;
-}
-
-/**
- Show selectable options to user and get the one that user select.
-
- @param PopupType Type of the popup to display.
- @param UserSelection User selection.
-
-**/
-VOID
-GetUserSelection (
- IN EFI_HII_POPUP_TYPE PopupType,
- OUT EFI_HII_POPUP_SELECTION *UserSelection
- )
-{
- LIST_ENTRY *HighlightPos;
- LIST_ENTRY *Link;
- USER_SELECTABLE_OPTION *SelectableOption;
- USER_SELECTABLE_OPTION *HighlightOption;
- EFI_INPUT_KEY KeyValue;
- EFI_STATUS Status;
-
- //
- // Display user selectable options in gUserSelectableOptions and get the option which user selects.
- //
- HighlightPos = gUserSelectableOptions.ForwardLink;
- do {
- for (Link = gUserSelectableOptions.ForwardLink; Link != &gUserSelectableOptions; Link = Link->ForwardLink) {
- SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);
- DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos));
- }
-
- //
- // If UserSelection is NULL, there is no need to handle the key user input, just return.
- //
- if (UserSelection == NULL) {
- return;
- }
-
- Status = WaitForKeyStroke (&KeyValue);
- ASSERT_EFI_ERROR (Status);
-
- HighlightOption = SELECTABLE_OPTION_FROM_LINK (HighlightPos);
- switch (KeyValue.UnicodeChar) {
- case CHAR_NULL:
- switch (KeyValue.ScanCode) {
- case SCAN_RIGHT:
- if (HighlightOption->Sequence < HighlightOption->MaxSequence) {
- HighlightPos = HighlightPos->ForwardLink;
- } else {
- HighlightPos = gUserSelectableOptions.ForwardLink;
- }
-
- break;
- case SCAN_LEFT:
- if (HighlightOption->Sequence > HighlightOption->MinSequence) {
- HighlightPos = HighlightPos->BackLink;
- } else {
- HighlightPos = gUserSelectableOptions.BackLink;
- }
-
- break;
- default:
- break;
- }
-
- break;
-
- case CHAR_CARRIAGE_RETURN:
- *UserSelection = HighlightOption->OptionType;
- return;
- default:
- if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptYes | UPPER_LOWER_CASE_OFFSET)) &&
- ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel)))
- {
- *UserSelection = EfiHiiPopupSelectionYes;
- return;
- } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptNo| UPPER_LOWER_CASE_OFFSET)) &&
- ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel)))
- {
- *UserSelection = EfiHiiPopupSelectionNo;
- return;
- } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptOk | UPPER_LOWER_CASE_OFFSET)) &&
- ((PopupType == EfiHiiPopupTypeOk) || (PopupType == EfiHiiPopupTypeOkCancel)))
- {
- *UserSelection = EfiHiiPopupSelectionOk;
- return;
- } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptCancel| UPPER_LOWER_CASE_OFFSET)) &&
- ((PopupType == EfiHiiPopupTypeOkCancel) || (PopupType == EfiHiiPopupTypeYesNoCancel)))
- {
- *UserSelection = EfiHiiPopupSelectionCancel;
- return;
- }
-
- break;
- }
- } while (TRUE);
-}
-
-/**
- Get the offset in the input string when the width reaches to a fixed one.
-
- The input string may contain NARROW_CHAR and WIDE_CHAR.
- Notice: the input string doesn't contain line break characters.
-
- @param String The input string to be counted.
- @param MaxWidth The max length this function supported.
- @param Offset The max index of the string can be show out. If string's width less than MaxWidth, offset will point to the "\0" of the string.
-
-**/
-VOID
-GetStringOffsetWithWidth (
- IN CHAR16 *String,
- IN UINTN MaxWidth,
- OUT UINTN *Offset
- )
-{
- UINTN StringWidth;
- UINTN CharWidth;
- UINTN StrOffset;
-
- StringWidth = 0;
- CharWidth = 1;
-
- for (StrOffset = 0; String[StrOffset] != CHAR_NULL; StrOffset++) {
- switch (String[StrOffset]) {
- case NARROW_CHAR:
- CharWidth = 1;
- break;
- case WIDE_CHAR:
- CharWidth = 2;
- break;
- default:
- StringWidth += CharWidth;
- if (StringWidth >= MaxWidth) {
- *Offset = StrOffset;
- return;
- }
- }
- }
-
- *Offset = StrOffset;
-}
-
-/**
- Parse the message to check if it contains line break characters.
- For once call, caller can get the string for one line and the width of the string.
- This function call be called recursively to parse the whole InputString.
-
- (Notice: current implementation, it only checks \r, \n characters, it deals \r,\n,\n\r same as \r\n.)
-
- @param InputString String description for this option.
- @param OutputString Buffer to copy the string into, caller is responsible for freeing the buffer.
- @param OutputStrWidth The width of OutputString.
- @param Index Where in InputString to start the copy process
-
- @return Returns the number of CHAR16 characters that were copied into the OutputString buffer, include the '\0' info.
-
-**/
-UINTN
-ParseMessageString (
- IN CHAR16 *InputString,
- OUT CHAR16 **OutputString,
- OUT UINTN *OutputStrWidth,
- IN OUT UINTN *Index
- )
-{
- UINTN StrOffset;
-
- if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) {
- return 0;
- }
-
- *OutputStrWidth = 0;
-
- //
- // Check the string to see if there are line break characters in the string
- //
- for (StrOffset = 0;
- InputString[*Index + StrOffset] != CHAR_CARRIAGE_RETURN && InputString[*Index + StrOffset] != CHAR_LINEFEED && InputString[*Index + StrOffset] != CHAR_NULL;
- StrOffset++
- )
- {
- }
-
- //
- // The CHAR_NULL has process last time, this time just return 0 to stand for finishing parsing the InputString.
- //
- if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) {
- return 0;
- }
-
- //
- // Copy the string to OutputString buffer and calculate the width of OutputString.
- //
- *OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof (CHAR16));
- if (*OutputString == NULL) {
- return 0;
- }
-
- CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof (CHAR16));
- *OutputStrWidth = (GetStringWidth (*OutputString) -2) / 2;
-
- //
- // Update the value of Index, can be used for marking where to check the input string for next call.
- //
- if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
- //
- // Skip the /n or /n/r info.
- //
- if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
- *Index = (*Index + StrOffset + 2);
- } else {
- *Index = (*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 = (*Index + StrOffset + 2);
- } else {
- *Index = (*Index + StrOffset + 1);
- }
- } else {
- *Index = (*Index + StrOffset);
- }
-
- return StrOffset + 1;
-}
-
-/**
- Calculate the position of the popup.
-
- @param PopupType Type of the popup to display.
- @param ScreenForPopup The screen dimensions for the popup.
-
-**/
-VOID
-CalculatePopupPosition (
- IN EFI_HII_POPUP_TYPE PopupType,
- OUT EFI_SCREEN_DESCRIPTOR *ScreenForPopup
- )
-{
- CHAR16 *OutputString;
- UINTN StringIndex;
- UINTN OutputStrWidth;
- UINTN OptionRowWidth;
- UINTN Columns;
- UINTN Rows;
-
- OptionRowWidth = 0;
-
- //
- // Calculate the row number which is needed to show the message string and the max width of the string in one row.
- //
- for (StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0;) {
- gMesStrLineNum++;
- if (gMaxRowWidth < OutputStrWidth) {
- gMaxRowWidth = OutputStrWidth;
- }
-
- FreePool (OutputString);
- }
-
- //
- // Calculate the row width for the selectable options.(OptionRowWidth = Number * SkipWidth + OptionWidth)
- //
- if (PopupType == EfiHiiPopupTypeOk) {
- OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *2 + USER_SELECTABLE_OPTION_OK_WIDTH;
- } else if (PopupType == EfiHiiPopupTypeOkCancel) {
- OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_OK_CAL_WIDTH;
- } else if (PopupType == EfiHiiPopupTypeYesNo) {
- OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_YES_NO_WIDTH;
- } else if (PopupType == EfiHiiPopupTypeYesNoCancel) {
- OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *4 + USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH;
- }
-
- if (OptionRowWidth > gMaxRowWidth) {
- gMaxRowWidth = OptionRowWidth;
- }
-
- //
- // Avialble row width for message string = screen width - left popup border width - right popup border width.
- // Avialble line number for message string = screen height - 1 - popup header height - popup footer height.
- // (Notice: screen height - 1 because in current UI page, the bottom row of srceen is usded to show Status Bar,not for form itself.
- // So we don't use the bottom row for popup either. If macro STATUS_BAR_HEIGHT changed, we also need to update the height here.)
- //
- // Select the smaller one between actual dimension of message string and the avialble dimension for message string.
- //
- gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows);
- gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER);
- gMesStrLineNum = MIN (gMesStrLineNum, Rows -1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT);
-
- //
- // Calculate the start column, end column, top row and bottom row for the popup.
- //
- ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2;
- ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1;
- ScreenForPopup->TopRow = (Rows - 1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT - gMesStrLineNum) / 2;
- ScreenForPopup->BottomRow = ScreenForPopup->TopRow + gMesStrLineNum + POPUP_FOOTER_HEIGHT + POPUP_HEADER_HEIGHT - 1;
-}
-
-/**
- Draw the Message box.
- +-------------------------------------------+
- | ERROR/WARNING/INFO |
- |-------------------------------------------|
- | popup messages |
- | |
- | user selectable options |
- +-------------------------------------------+
-
- @param PopupStyle Popup style to use.
-
-**/
-EFI_STATUS
-DrawMessageBox (
- IN EFI_HII_POPUP_STYLE PopupStyle
- )
-{
- UINTN Index;
- UINTN Length;
- UINTN EndCol;
- UINTN TopRow;
- UINTN StartCol;
- UINTN BottomRow;
- CHAR16 Character;
- UINTN DisplayRow;
- UINTN StringIndex;
- CHAR16 *TempString;
- CHAR16 *OutputString;
- UINTN ColDimension;
- UINTN OutputStrWidth;
- UINTN DrawMesStrRowNum;
-
- EndCol = gPopupDimensions.RightColumn;
- TopRow = gPopupDimensions.TopRow;
- StartCol = gPopupDimensions.LeftColumn;
- BottomRow = gPopupDimensions.BottomRow;
- ColDimension = EndCol - StartCol + 1;
- DrawMesStrRowNum = 0;
-
- //
- // 1. Draw the top of the message box.
- //
- Character = BOXDRAW_DOWN_RIGHT;
- PrintCharAt (StartCol, TopRow, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = StartCol; Index + 1 < EndCol; Index++) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
-
- //
- // 2. Draw the prompt string for different popup styles.
- //
- Character = BOXDRAW_VERTICAL;
- DisplayRow = TopRow + POPUP_BORDER;
- ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
- PrintCharAt (StartCol, DisplayRow, Character);
- PrintCharAt (EndCol, DisplayRow, Character);
- if (PopupStyle == EfiHiiPopupStyleError) {
- PrintStringAt ((ColDimension - (GetStringWidth (gErrorPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gErrorPopup);
- } else if (PopupStyle == EfiHiiPopupStyleWarning) {
- PrintStringAt ((ColDimension - (GetStringWidth (gWarningPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gWarningPopup);
- } else {
- PrintStringAt ((ColDimension - (GetStringWidth (gInfoPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gInfoPopup);
- }
-
- //
- // 3. Draw the horizontal line below the prompt string for different popup styles.
- //
- DisplayRow = TopRow + POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT;
- ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
- Character = BOXDRAW_HORIZONTAL;
- for (Index = StartCol + 1; Index < EndCol; Index++) {
- PrintCharAt (Index, DisplayRow, Character);
- }
-
- Character = BOXDRAW_VERTICAL;
- PrintCharAt (StartCol, DisplayRow, Character);
- PrintCharAt (EndCol, DisplayRow, Character);
-
- //
- // 4. Draw the mesage string.
- //
- DisplayRow = TopRow + POPUP_HEADER_HEIGHT;
- for (Index = DisplayRow, StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) {
- ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());
- PrintCharAt (StartCol, Index, Character);
- PrintCharAt (EndCol, Index, Character);
- if (OutputStrWidth > gMaxRowWidth) {
- //
- // OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead.
- //
- GetStringOffsetWithWidth (OutputString, gMaxRowWidth, &Length);
- TempString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
- if (TempString == NULL) {
- FreePool (OutputString);
- return EFI_OUT_OF_RESOURCES;
- }
-
- StrnCpyS (TempString, Length + 1, OutputString, Length - 3);
- StrCatS (TempString, Length + 1, L"...");
- PrintStringAt ((ColDimension - gMaxRowWidth) / 2 + StartCol, Index, TempString);
- FreePool (TempString);
- } else {
- PrintStringAt ((ColDimension - OutputStrWidth) / 2 + StartCol, Index, OutputString);
- }
-
- Index++;
- DrawMesStrRowNum++;
- FreePool (OutputString);
- }
-
- //
- // 5. Draw an empty line after message string.
- //
- ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());
- PrintCharAt (StartCol, Index, Character);
- PrintCharAt (EndCol, Index, Character);
- //
- // Check whether the actual string row number beyond the MesStrRowNum, if yes, print the ...... in the row.
- //
- if ((OutputStrWidth > 0) && (DrawMesStrRowNum >= gMesStrLineNum)) {
- PrintStringAt ((ColDimension - StrLen (L"......")) / 2 + StartCol, Index, L"......");
- }
-
- //
- // 6. Draw an empty line which is used to show user selectable options, will draw concrete option strings in function GetUserSelection().
- //
- Character = BOXDRAW_VERTICAL;
- DisplayRow = BottomRow - POPUP_BORDER;
- ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
- PrintCharAt (StartCol, DisplayRow, Character);
- PrintCharAt (EndCol, DisplayRow, Character);
-
- //
- // 7. Draw the bottom of the message box.
- //
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (StartCol, BottomRow, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = StartCol; Index + 1 < EndCol; Index++) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_UP_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
-
- return EFI_SUCCESS;
-}
-
-/**
- Displays a popup window.
-
- @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance.
- @param PopupStyle Popup style to use.
- @param PopupType Type of the popup to display.
- @param HiiHandle HII handle of the string pack containing Message
- @param Message A message to display in the popup box.
- @param UserSelection User selection.
-
- @retval EFI_SUCCESS The popup box was successfully displayed.
- @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string.
- @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box.
-
-**/
-EFI_STATUS
-EFIAPI
-CreatePopup (
- IN EFI_HII_POPUP_PROTOCOL *This,
- IN EFI_HII_POPUP_STYLE PopupStyle,
- IN EFI_HII_POPUP_TYPE PopupType,
- IN EFI_HII_HANDLE HiiHandle,
- IN EFI_STRING_ID Message,
- OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL
- )
-{
- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
- EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
- EFI_STATUS Status;
-
- if ((PopupType < EfiHiiPopupTypeOk) || (PopupType > EfiHiiPopupTypeYesNoCancel)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((HiiHandle == NULL) || (Message == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- gMessageString = HiiGetString (HiiHandle, Message, NULL);
- if (gMessageString == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ConOut = gST->ConOut;
- gMaxRowWidth = 0;
- gMesStrLineNum = 0;
-
- CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));
- ConOut->EnableCursor (ConOut, FALSE);
- ConOut->SetAttribute (ConOut, GetPopupColor ());
-
- CalculatePopupPosition (PopupType, &gPopupDimensions);
-
- Status = DrawMessageBox (PopupStyle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Add user selectable options to option list: gUserSelectableOptions
- //
- Status = AddUserSelectableOptions (PopupType);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- GetUserSelection (PopupType, UserSelection);
-
-Done:
- //
- // Restore Conout attributes and free the resources allocate before.
- //
- ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible);
- ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
- ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute);
- FreeSelectableOptions (&gUserSelectableOptions);
- FreePool (gMessageString);
-
- return Status;
-}
+/** @file +Implementation for Hii Popup Protocol. + +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FormDisplay.h" + +EFI_SCREEN_DESCRIPTOR gPopupDimensions; +LIST_ENTRY gUserSelectableOptions; +EFI_STRING gMessageString; +UINTN gMesStrLineNum; +UINTN gMaxRowWidth; + +/** + Free the user selectable option structure data. + + @param OptionList Point to the selectable option list which need to be freed. + +**/ +VOID +FreeSelectableOptions ( + LIST_ENTRY *OptionList + ) +{ + LIST_ENTRY *Link; + USER_SELECTABLE_OPTION *SelectableOption; + + while (!IsListEmpty (OptionList)) { + Link = GetFirstNode (OptionList); + SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link); + RemoveEntryList (&SelectableOption->Link); + FreePool (SelectableOption); + } +} + +/** + Display one selectable option. + + @param SelectableOption The selectable option need to be drew. + @param Highlight Whether the option need to be highlighted. + +**/ +VOID +DisplayOneSelectableOption ( + IN USER_SELECTABLE_OPTION *SelectableOption, + IN BOOLEAN Highlight + ) +{ + if (Highlight) { + gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); + } + + PrintStringAt (SelectableOption->OptionCol, SelectableOption->OptionRow, SelectableOption->OptionString); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); +} + +/** + Add one selectable option to option list. This is the work function for AddUserSelectableOptions. + + @param PopupType The option need to be drew. + @param OptionType The type of this selection option. + @param OptionString Point to the option string that to be shown. + @param OptionCol The column that the option need to be drew at. + @param OptionRow The row that the option need to be drew at. + + @retval EFI_SUCCESS This function implement successfully. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available. + +**/ +EFI_STATUS +AddOneSelectableOption ( + IN EFI_HII_POPUP_TYPE PopupType, + IN EFI_HII_POPUP_SELECTION OptionType, + IN CHAR16 *OptionString, + IN UINTN OptionCol, + IN UINTN OptionRow + ) +{ + USER_SELECTABLE_OPTION *UserSelectableOption; + + UserSelectableOption = AllocateZeroPool (sizeof (USER_SELECTABLE_OPTION)); + if (UserSelectableOption == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize the user selectable option based on the PopupType and OptionType. + // And then add the option to the option list gUserSelectableOptions. + // + UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE; + UserSelectableOption->OptionString = OptionString; + UserSelectableOption->OptionType = OptionType; + UserSelectableOption->OptionCol = OptionCol; + UserSelectableOption->OptionRow = OptionRow; + UserSelectableOption->MinSequence = 0; + + switch (PopupType) { + case EfiHiiPopupTypeOk: + UserSelectableOption->MaxSequence = 0; + UserSelectableOption->Sequence = 0; + break; + case EfiHiiPopupTypeOkCancel: + UserSelectableOption->MaxSequence = 1; + if (OptionType == EfiHiiPopupSelectionOk) { + UserSelectableOption->Sequence = 0; + } else { + UserSelectableOption->Sequence = 1; + } + + break; + case EfiHiiPopupTypeYesNo: + UserSelectableOption->MaxSequence = 1; + if (OptionType == EfiHiiPopupSelectionYes) { + UserSelectableOption->Sequence = 0; + } else { + UserSelectableOption->Sequence = 1; + } + + break; + case EfiHiiPopupTypeYesNoCancel: + UserSelectableOption->MaxSequence = 2; + if (OptionType == EfiHiiPopupSelectionYes) { + UserSelectableOption->Sequence = 0; + } else if (OptionType == EfiHiiPopupSelectionNo) { + UserSelectableOption->Sequence = 1; + } else { + UserSelectableOption->Sequence = 2; + } + + break; + default: + break; + } + + InsertTailList (&gUserSelectableOptions, &UserSelectableOption->Link); + + return EFI_SUCCESS; +} + +/** + Add user selectable options to option list for different types of Popup. + + @param PopupType Type of the popup to display. + + @retval EFI_SUCCESS This function implement successfully. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available. + +**/ +EFI_STATUS +AddUserSelectableOptions ( + IN EFI_HII_POPUP_TYPE PopupType + ) +{ + EFI_STATUS Status; + UINTN EndCol; + UINTN StartCol; + UINTN OptionCol; + UINTN OptionRow; + UINTN ColDimension; + + Status = EFI_SUCCESS; + EndCol = gPopupDimensions.RightColumn; + StartCol = gPopupDimensions.LeftColumn; + OptionRow = gPopupDimensions.BottomRow - POPUP_BORDER; + ColDimension = EndCol - StartCol + 1; + + InitializeListHead (&gUserSelectableOptions); + + switch (PopupType) { + case EfiHiiPopupTypeOk: + // + // Add [Ok] option to the option list. + // + OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_WIDTH) / 2; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow); + break; + case EfiHiiPopupTypeOkCancel: + // + // Add [Ok] and [Cancel] options to the option list. + // + OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow); + OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3 - (GetStringWidth (gCancelOption) -2) / 2 + 1; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow); + break; + case EfiHiiPopupTypeYesNo: + // + // Add [Yes] and [No] options to the option list. + // + OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow); + OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3 - (GetStringWidth (gNoOption)- 2) / 2 + 1; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow); + break; + case EfiHiiPopupTypeYesNoCancel: + // + // Add [Yes], [No] and [Cancel] options to the option list. + // + OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow); + OptionCol = StartCol + (ColDimension - (GetStringWidth (gNoOption) -2) / 2) / 2; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow); + OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4 - (GetStringWidth (gCancelOption) - 2) / 2 + 1; + Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow); + break; + default: + break; + } + + return Status; +} + +/** + Show selectable options to user and get the one that user select. + + @param PopupType Type of the popup to display. + @param UserSelection User selection. + +**/ +VOID +GetUserSelection ( + IN EFI_HII_POPUP_TYPE PopupType, + OUT EFI_HII_POPUP_SELECTION *UserSelection + ) +{ + LIST_ENTRY *HighlightPos; + LIST_ENTRY *Link; + USER_SELECTABLE_OPTION *SelectableOption; + USER_SELECTABLE_OPTION *HighlightOption; + EFI_INPUT_KEY KeyValue; + EFI_STATUS Status; + + // + // Display user selectable options in gUserSelectableOptions and get the option which user selects. + // + HighlightPos = gUserSelectableOptions.ForwardLink; + do { + for (Link = gUserSelectableOptions.ForwardLink; Link != &gUserSelectableOptions; Link = Link->ForwardLink) { + SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link); + DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos)); + } + + // + // If UserSelection is NULL, there is no need to handle the key user input, just return. + // + if (UserSelection == NULL) { + return; + } + + Status = WaitForKeyStroke (&KeyValue); + ASSERT_EFI_ERROR (Status); + + HighlightOption = SELECTABLE_OPTION_FROM_LINK (HighlightPos); + switch (KeyValue.UnicodeChar) { + case CHAR_NULL: + switch (KeyValue.ScanCode) { + case SCAN_RIGHT: + if (HighlightOption->Sequence < HighlightOption->MaxSequence) { + HighlightPos = HighlightPos->ForwardLink; + } else { + HighlightPos = gUserSelectableOptions.ForwardLink; + } + + break; + case SCAN_LEFT: + if (HighlightOption->Sequence > HighlightOption->MinSequence) { + HighlightPos = HighlightPos->BackLink; + } else { + HighlightPos = gUserSelectableOptions.BackLink; + } + + break; + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + *UserSelection = HighlightOption->OptionType; + return; + default: + if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptYes | UPPER_LOWER_CASE_OFFSET)) && + ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel))) + { + *UserSelection = EfiHiiPopupSelectionYes; + return; + } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptNo| UPPER_LOWER_CASE_OFFSET)) && + ((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel))) + { + *UserSelection = EfiHiiPopupSelectionNo; + return; + } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptOk | UPPER_LOWER_CASE_OFFSET)) && + ((PopupType == EfiHiiPopupTypeOk) || (PopupType == EfiHiiPopupTypeOkCancel))) + { + *UserSelection = EfiHiiPopupSelectionOk; + return; + } else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptCancel| UPPER_LOWER_CASE_OFFSET)) && + ((PopupType == EfiHiiPopupTypeOkCancel) || (PopupType == EfiHiiPopupTypeYesNoCancel))) + { + *UserSelection = EfiHiiPopupSelectionCancel; + return; + } + + break; + } + } while (TRUE); +} + +/** + Get the offset in the input string when the width reaches to a fixed one. + + The input string may contain NARROW_CHAR and WIDE_CHAR. + Notice: the input string doesn't contain line break characters. + + @param String The input string to be counted. + @param MaxWidth The max length this function supported. + @param Offset The max index of the string can be show out. If string's width less than MaxWidth, offset will point to the "\0" of the string. + +**/ +VOID +GetStringOffsetWithWidth ( + IN CHAR16 *String, + IN UINTN MaxWidth, + OUT UINTN *Offset + ) +{ + UINTN StringWidth; + UINTN CharWidth; + UINTN StrOffset; + + StringWidth = 0; + CharWidth = 1; + + for (StrOffset = 0; String[StrOffset] != CHAR_NULL; StrOffset++) { + switch (String[StrOffset]) { + case NARROW_CHAR: + CharWidth = 1; + break; + case WIDE_CHAR: + CharWidth = 2; + break; + default: + StringWidth += CharWidth; + if (StringWidth >= MaxWidth) { + *Offset = StrOffset; + return; + } + } + } + + *Offset = StrOffset; +} + +/** + Parse the message to check if it contains line break characters. + For once call, caller can get the string for one line and the width of the string. + This function call be called recursively to parse the whole InputString. + + (Notice: current implementation, it only checks \r, \n characters, it deals \r,\n,\n\r same as \r\n.) + + @param InputString String description for this option. + @param OutputString Buffer to copy the string into, caller is responsible for freeing the buffer. + @param OutputStrWidth The width of OutputString. + @param Index Where in InputString to start the copy process + + @return Returns the number of CHAR16 characters that were copied into the OutputString buffer, include the '\0' info. + +**/ +UINTN +ParseMessageString ( + IN CHAR16 *InputString, + OUT CHAR16 **OutputString, + OUT UINTN *OutputStrWidth, + IN OUT UINTN *Index + ) +{ + UINTN StrOffset; + + if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) { + return 0; + } + + *OutputStrWidth = 0; + + // + // Check the string to see if there are line break characters in the string + // + for (StrOffset = 0; + InputString[*Index + StrOffset] != CHAR_CARRIAGE_RETURN && InputString[*Index + StrOffset] != CHAR_LINEFEED && InputString[*Index + StrOffset] != CHAR_NULL; + StrOffset++ + ) + { + } + + // + // The CHAR_NULL has process last time, this time just return 0 to stand for finishing parsing the InputString. + // + if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) { + return 0; + } + + // + // Copy the string to OutputString buffer and calculate the width of OutputString. + // + *OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof (CHAR16)); + if (*OutputString == NULL) { + return 0; + } + + CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof (CHAR16)); + *OutputStrWidth = (GetStringWidth (*OutputString) -2) / 2; + + // + // Update the value of Index, can be used for marking where to check the input string for next call. + // + if (InputString[*Index + StrOffset] == CHAR_LINEFEED) { + // + // Skip the /n or /n/r info. + // + if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) { + *Index = (*Index + StrOffset + 2); + } else { + *Index = (*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 = (*Index + StrOffset + 2); + } else { + *Index = (*Index + StrOffset + 1); + } + } else { + *Index = (*Index + StrOffset); + } + + return StrOffset + 1; +} + +/** + Calculate the position of the popup. + + @param PopupType Type of the popup to display. + @param ScreenForPopup The screen dimensions for the popup. + +**/ +VOID +CalculatePopupPosition ( + IN EFI_HII_POPUP_TYPE PopupType, + OUT EFI_SCREEN_DESCRIPTOR *ScreenForPopup + ) +{ + CHAR16 *OutputString; + UINTN StringIndex; + UINTN OutputStrWidth; + UINTN OptionRowWidth; + UINTN Columns; + UINTN Rows; + + OptionRowWidth = 0; + + // + // Calculate the row number which is needed to show the message string and the max width of the string in one row. + // + for (StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0;) { + gMesStrLineNum++; + if (gMaxRowWidth < OutputStrWidth) { + gMaxRowWidth = OutputStrWidth; + } + + FreePool (OutputString); + } + + // + // Calculate the row width for the selectable options.(OptionRowWidth = Number * SkipWidth + OptionWidth) + // + if (PopupType == EfiHiiPopupTypeOk) { + OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *2 + USER_SELECTABLE_OPTION_OK_WIDTH; + } else if (PopupType == EfiHiiPopupTypeOkCancel) { + OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_OK_CAL_WIDTH; + } else if (PopupType == EfiHiiPopupTypeYesNo) { + OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_YES_NO_WIDTH; + } else if (PopupType == EfiHiiPopupTypeYesNoCancel) { + OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *4 + USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH; + } + + if (OptionRowWidth > gMaxRowWidth) { + gMaxRowWidth = OptionRowWidth; + } + + // + // Avialble row width for message string = screen width - left popup border width - right popup border width. + // Avialble line number for message string = screen height - 1 - popup header height - popup footer height. + // (Notice: screen height - 1 because in current UI page, the bottom row of srceen is usded to show Status Bar,not for form itself. + // So we don't use the bottom row for popup either. If macro STATUS_BAR_HEIGHT changed, we also need to update the height here.) + // + // Select the smaller one between actual dimension of message string and the avialble dimension for message string. + // + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows); + gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER); + gMesStrLineNum = MIN (gMesStrLineNum, Rows -1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT); + + // + // Calculate the start column, end column, top row and bottom row for the popup. + // + ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2; + ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1; + ScreenForPopup->TopRow = (Rows - 1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT - gMesStrLineNum) / 2; + ScreenForPopup->BottomRow = ScreenForPopup->TopRow + gMesStrLineNum + POPUP_FOOTER_HEIGHT + POPUP_HEADER_HEIGHT - 1; +} + +/** + Draw the Message box. + +-------------------------------------------+ + | ERROR/WARNING/INFO | + |-------------------------------------------| + | popup messages | + | | + | user selectable options | + +-------------------------------------------+ + + @param PopupStyle Popup style to use. + +**/ +EFI_STATUS +DrawMessageBox ( + IN EFI_HII_POPUP_STYLE PopupStyle + ) +{ + UINTN Index; + UINTN Length; + UINTN EndCol; + UINTN TopRow; + UINTN StartCol; + UINTN BottomRow; + CHAR16 Character; + UINTN DisplayRow; + UINTN StringIndex; + CHAR16 *TempString; + CHAR16 *OutputString; + UINTN ColDimension; + UINTN OutputStrWidth; + UINTN DrawMesStrRowNum; + + EndCol = gPopupDimensions.RightColumn; + TopRow = gPopupDimensions.TopRow; + StartCol = gPopupDimensions.LeftColumn; + BottomRow = gPopupDimensions.BottomRow; + ColDimension = EndCol - StartCol + 1; + DrawMesStrRowNum = 0; + + // + // 1. Draw the top of the message box. + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (StartCol, TopRow, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = StartCol; Index + 1 < EndCol; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + + // + // 2. Draw the prompt string for different popup styles. + // + Character = BOXDRAW_VERTICAL; + DisplayRow = TopRow + POPUP_BORDER; + ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); + PrintCharAt (StartCol, DisplayRow, Character); + PrintCharAt (EndCol, DisplayRow, Character); + if (PopupStyle == EfiHiiPopupStyleError) { + PrintStringAt ((ColDimension - (GetStringWidth (gErrorPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gErrorPopup); + } else if (PopupStyle == EfiHiiPopupStyleWarning) { + PrintStringAt ((ColDimension - (GetStringWidth (gWarningPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gWarningPopup); + } else { + PrintStringAt ((ColDimension - (GetStringWidth (gInfoPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gInfoPopup); + } + + // + // 3. Draw the horizontal line below the prompt string for different popup styles. + // + DisplayRow = TopRow + POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT; + ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); + Character = BOXDRAW_HORIZONTAL; + for (Index = StartCol + 1; Index < EndCol; Index++) { + PrintCharAt (Index, DisplayRow, Character); + } + + Character = BOXDRAW_VERTICAL; + PrintCharAt (StartCol, DisplayRow, Character); + PrintCharAt (EndCol, DisplayRow, Character); + + // + // 4. Draw the mesage string. + // + DisplayRow = TopRow + POPUP_HEADER_HEIGHT; + for (Index = DisplayRow, StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) { + ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ()); + PrintCharAt (StartCol, Index, Character); + PrintCharAt (EndCol, Index, Character); + if (OutputStrWidth > gMaxRowWidth) { + // + // OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead. + // + GetStringOffsetWithWidth (OutputString, gMaxRowWidth, &Length); + TempString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); + if (TempString == NULL) { + FreePool (OutputString); + return EFI_OUT_OF_RESOURCES; + } + + StrnCpyS (TempString, Length + 1, OutputString, Length - 3); + StrCatS (TempString, Length + 1, L"..."); + PrintStringAt ((ColDimension - gMaxRowWidth) / 2 + StartCol, Index, TempString); + FreePool (TempString); + } else { + PrintStringAt ((ColDimension - OutputStrWidth) / 2 + StartCol, Index, OutputString); + } + + Index++; + DrawMesStrRowNum++; + FreePool (OutputString); + } + + // + // 5. Draw an empty line after message string. + // + ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ()); + PrintCharAt (StartCol, Index, Character); + PrintCharAt (EndCol, Index, Character); + // + // Check whether the actual string row number beyond the MesStrRowNum, if yes, print the ...... in the row. + // + if ((OutputStrWidth > 0) && (DrawMesStrRowNum >= gMesStrLineNum)) { + PrintStringAt ((ColDimension - StrLen (L"......")) / 2 + StartCol, Index, L"......"); + } + + // + // 6. Draw an empty line which is used to show user selectable options, will draw concrete option strings in function GetUserSelection(). + // + Character = BOXDRAW_VERTICAL; + DisplayRow = BottomRow - POPUP_BORDER; + ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); + PrintCharAt (StartCol, DisplayRow, Character); + PrintCharAt (EndCol, DisplayRow, Character); + + // + // 7. Draw the bottom of the message box. + // + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (StartCol, BottomRow, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = StartCol; Index + 1 < EndCol; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + + return EFI_SUCCESS; +} + +/** + Displays a popup window. + + @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance. + @param PopupStyle Popup style to use. + @param PopupType Type of the popup to display. + @param HiiHandle HII handle of the string pack containing Message + @param Message A message to display in the popup box. + @param UserSelection User selection. + + @retval EFI_SUCCESS The popup box was successfully displayed. + @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string. + @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box. + +**/ +EFI_STATUS +EFIAPI +CreatePopup ( + IN EFI_HII_POPUP_PROTOCOL *This, + IN EFI_HII_POPUP_STYLE PopupStyle, + IN EFI_HII_POPUP_TYPE PopupType, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID Message, + OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode; + EFI_STATUS Status; + + if ((PopupType < EfiHiiPopupTypeOk) || (PopupType > EfiHiiPopupTypeYesNoCancel)) { + return EFI_INVALID_PARAMETER; + } + + if ((HiiHandle == NULL) || (Message == 0)) { + return EFI_INVALID_PARAMETER; + } + + gMessageString = HiiGetString (HiiHandle, Message, NULL); + if (gMessageString == NULL) { + return EFI_INVALID_PARAMETER; + } + + ConOut = gST->ConOut; + gMaxRowWidth = 0; + gMesStrLineNum = 0; + + CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode)); + ConOut->EnableCursor (ConOut, FALSE); + ConOut->SetAttribute (ConOut, GetPopupColor ()); + + CalculatePopupPosition (PopupType, &gPopupDimensions); + + Status = DrawMessageBox (PopupStyle); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add user selectable options to option list: gUserSelectableOptions + // + Status = AddUserSelectableOptions (PopupType); + if (EFI_ERROR (Status)) { + goto Done; + } + + GetUserSelection (PopupType, UserSelection); + +Done: + // + // Restore Conout attributes and free the resources allocate before. + // + ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible); + ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); + ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute); + FreeSelectableOptions (&gUserSelectableOptions); + FreePool (gMessageString); + + return Status; +} diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c index 0d4cfa4cf0..14bee5836b 100644 --- a/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c +++ b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c @@ -1,1617 +1,1617 @@ -/** @file
-Implementation for handling the User Interface option processing.
-
-
-Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FormDisplay.h"
-
-#define MAX_TIME_OUT_LEN 0x10
-
-/**
- Concatenate a narrow string to another string.
-
- @param Destination The destination string.
- @param DestMax The Max length of destination string.
- @param Source The source string. The string to be concatenated.
- to the end of Destination.
-
-**/
-VOID
-NewStrCat (
- IN OUT CHAR16 *Destination,
- IN UINTN DestMax,
- IN CHAR16 *Source
- )
-{
- UINTN Length;
-
- for (Length = 0; Destination[Length] != 0; Length++) {
- }
-
- //
- // We now have the length of the original string
- // We can safely assume for now that we are concatenating a narrow value to this string.
- // For instance, the string is "XYZ" and cat'ing ">"
- // If this assumption changes, we need to make this routine a bit more complex
- //
- Destination[Length] = NARROW_CHAR;
- Length++;
-
- StrCpyS (Destination + Length, DestMax - Length, Source);
-}
-
-/**
- Get UINT64 type value.
-
- @param Value Input Hii value.
-
- @retval UINT64 Return the UINT64 type value.
-
-**/
-UINT64
-HiiValueToUINT64 (
- IN EFI_HII_VALUE *Value
- )
-{
- UINT64 RetVal;
-
- RetVal = 0;
-
- switch (Value->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- RetVal = Value->Value.u8;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- RetVal = Value->Value.u16;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- RetVal = Value->Value.u32;
- break;
-
- case EFI_IFR_TYPE_BOOLEAN:
- RetVal = Value->Value.b;
- break;
-
- case EFI_IFR_TYPE_DATE:
- RetVal = *(UINT64 *)&Value->Value.date;
- break;
-
- case EFI_IFR_TYPE_TIME:
- RetVal = (*(UINT64 *)&Value->Value.time) & 0xffffff;
- break;
-
- default:
- RetVal = Value->Value.u64;
- break;
- }
-
- return RetVal;
-}
-
-/**
- Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
-
- EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
- EFI_IFR_TYPE_BUFFER when do the value compare.
-
- @param Value Expression value to compare on.
-
- @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
- @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
-
-**/
-BOOLEAN
-IsTypeInBuffer (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_BUFFER:
- case EFI_IFR_TYPE_DATE:
- case EFI_IFR_TYPE_TIME:
- case EFI_IFR_TYPE_REF:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-/**
- Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
-
- @param Value Expression value to compare on.
-
- @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
- @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
-
-**/
-BOOLEAN
-IsTypeInUINT64 (
- IN EFI_HII_VALUE *Value
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- case EFI_IFR_TYPE_NUM_SIZE_16:
- case EFI_IFR_TYPE_NUM_SIZE_32:
- case EFI_IFR_TYPE_NUM_SIZE_64:
- case EFI_IFR_TYPE_BOOLEAN:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-/**
- Return the buffer length and buffer pointer for this value.
-
- EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
- EFI_IFR_TYPE_BUFFER when do the value compare.
-
- @param Value Expression value to compare on.
- @param Buf Return the buffer pointer.
- @param BufLen Return the buffer length.
-
-**/
-VOID
-GetBufAndLenForValue (
- IN EFI_HII_VALUE *Value,
- OUT UINT8 **Buf,
- OUT UINT16 *BufLen
- )
-{
- switch (Value->Type) {
- case EFI_IFR_TYPE_BUFFER:
- *Buf = Value->Buffer;
- *BufLen = Value->BufferLen;
- break;
-
- case EFI_IFR_TYPE_DATE:
- *Buf = (UINT8 *)(&Value->Value.date);
- *BufLen = (UINT16)sizeof (EFI_HII_DATE);
- break;
-
- case EFI_IFR_TYPE_TIME:
- *Buf = (UINT8 *)(&Value->Value.time);
- *BufLen = (UINT16)sizeof (EFI_HII_TIME);
- break;
-
- case EFI_IFR_TYPE_REF:
- *Buf = (UINT8 *)(&Value->Value.ref);
- *BufLen = (UINT16)sizeof (EFI_HII_REF);
- break;
-
- default:
- *Buf = NULL;
- *BufLen = 0;
- }
-}
-
-/**
- Compare two Hii value.
-
- @param Value1 Expression value to compare on left-hand.
- @param Value2 Expression value to compare on right-hand.
- @param Result Return value after compare.
- retval 0 Two operators equal.
- return Positive value if Value1 is greater than Value2.
- retval Negative value if Value1 is less than Value2.
- @param HiiHandle Only required for string compare.
-
- @retval other Could not perform compare on two values.
- @retval EFI_SUCCESS Compare the value success.
-
-**/
-EFI_STATUS
-CompareHiiValue (
- IN EFI_HII_VALUE *Value1,
- IN EFI_HII_VALUE *Value2,
- OUT INTN *Result,
- IN EFI_HII_HANDLE HiiHandle OPTIONAL
- )
-{
- INT64 Temp64;
- CHAR16 *Str1;
- CHAR16 *Str2;
- UINTN Len;
- UINT8 *Buf1;
- UINT16 Buf1Len;
- UINT8 *Buf2;
- UINT16 Buf2Len;
-
- if ((Value1->Type == EFI_IFR_TYPE_STRING) && (Value2->Type == EFI_IFR_TYPE_STRING)) {
- if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) {
- //
- // StringId 0 is reserved
- //
- return EFI_INVALID_PARAMETER;
- }
-
- if (Value1->Value.string == Value2->Value.string) {
- *Result = 0;
- return EFI_SUCCESS;
- }
-
- Str1 = GetToken (Value1->Value.string, HiiHandle);
- if (Str1 == NULL) {
- //
- // String not found
- //
- return EFI_NOT_FOUND;
- }
-
- Str2 = GetToken (Value2->Value.string, HiiHandle);
- if (Str2 == NULL) {
- FreePool (Str1);
- return EFI_NOT_FOUND;
- }
-
- *Result = StrCmp (Str1, Str2);
-
- FreePool (Str1);
- FreePool (Str2);
-
- return EFI_SUCCESS;
- }
-
- //
- // Take types(date, time, ref, buffer) as buffer
- //
- if (IsTypeInBuffer (Value1) && IsTypeInBuffer (Value2)) {
- GetBufAndLenForValue (Value1, &Buf1, &Buf1Len);
- GetBufAndLenForValue (Value2, &Buf2, &Buf2Len);
-
- Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
- *Result = CompareMem (Buf1, Buf2, Len);
- if ((*Result == 0) && (Buf1Len != Buf2Len)) {
- //
- // In this case, means base on samll number buffer, the data is same
- // So which value has more data, which value is bigger.
- //
- *Result = Buf1Len > Buf2Len ? 1 : -1;
- }
-
- return EFI_SUCCESS;
- }
-
- //
- // Take remain types(integer, boolean, date/time) as integer
- //
- if (IsTypeInUINT64 (Value1) && IsTypeInUINT64 (Value2)) {
- Temp64 = HiiValueToUINT64 (Value1) - HiiValueToUINT64 (Value2);
- if (Temp64 > 0) {
- *Result = 1;
- } else if (Temp64 < 0) {
- *Result = -1;
- } else {
- *Result = 0;
- }
-
- return EFI_SUCCESS;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- Search an Option of a Question by its value.
-
- @param Question The Question
- @param OptionValue Value for Option to be searched.
-
- @retval Pointer Pointer to the found Option.
- @retval NULL Option not found.
-
-**/
-DISPLAY_QUESTION_OPTION *
-ValueToOption (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
- IN EFI_HII_VALUE *OptionValue
- )
-{
- LIST_ENTRY *Link;
- DISPLAY_QUESTION_OPTION *Option;
- INTN Result;
- EFI_HII_VALUE Value;
-
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
-
- ZeroMem (&Value, sizeof (EFI_HII_VALUE));
- Value.Type = Option->OptionOpCode->Type;
- CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
-
- if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
- return Option;
- }
-
- Link = GetNextNode (&Question->OptionListHead, Link);
- }
-
- return NULL;
-}
-
-/**
- Return data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
-
- @retval Value The data to be returned
-
-**/
-UINT64
-GetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index
- )
-{
- UINT64 Data;
-
- ASSERT (Array != NULL);
-
- Data = 0;
- switch (Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- Data = (UINT64)*(((UINT8 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- Data = (UINT64)*(((UINT16 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- Data = (UINT64)*(((UINT32 *)Array) + Index);
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- Data = (UINT64)*(((UINT64 *)Array) + Index);
- break;
-
- default:
- break;
- }
-
- return Data;
-}
-
-/**
- Set value of a data element in an Array by its Index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Index Zero based index for data in this array.
- @param Value The value to be set.
-
-**/
-VOID
-SetArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINTN Index,
- IN UINT64 Value
- )
-{
- ASSERT (Array != NULL);
-
- switch (Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- *(((UINT8 *)Array) + Index) = (UINT8)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- *(((UINT16 *)Array) + Index) = (UINT16)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- *(((UINT32 *)Array) + Index) = (UINT32)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- *(((UINT64 *)Array) + Index) = (UINT64)Value;
- break;
-
- default:
- break;
- }
-}
-
-/**
- Check whether this value already in the array, if yes, return the index.
-
- @param Array The data array.
- @param Type Type of the data in this array.
- @param Value The value to be find.
- @param Index The index in the array which has same value with Value.
-
- @retval TRUE Found the value in the array.
- @retval FALSE Not found the value.
-
-**/
-BOOLEAN
-FindArrayData (
- IN VOID *Array,
- IN UINT8 Type,
- IN UINT64 Value,
- OUT UINTN *Index OPTIONAL
- )
-{
- UINTN Count;
- UINT64 TmpValue;
- UINT64 ValueComp;
-
- ASSERT (Array != NULL);
-
- Count = 0;
- TmpValue = 0;
-
- switch (Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- ValueComp = (UINT8)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- ValueComp = (UINT16)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- ValueComp = (UINT32)Value;
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_64:
- ValueComp = (UINT64)Value;
- break;
-
- default:
- ValueComp = 0;
- break;
- }
-
- while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
- if (ValueComp == TmpValue) {
- if (Index != NULL) {
- *Index = Count;
- }
-
- return TRUE;
- }
-
- Count++;
- }
-
- return FALSE;
-}
-
-/**
- Print Question Value according to it's storage width and display attributes.
-
- @param Question The Question to be printed.
- @param FormattedNumber Buffer for output string.
- @param BufferSize The FormattedNumber buffer size in bytes.
-
- @retval EFI_SUCCESS Print success.
- @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
-
-**/
-EFI_STATUS
-PrintFormattedNumber (
- IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
- IN OUT CHAR16 *FormattedNumber,
- IN UINTN BufferSize
- )
-{
- INT64 Value;
- CHAR16 *Format;
- EFI_HII_VALUE *QuestionValue;
- EFI_IFR_NUMERIC *NumericOp;
-
- if (BufferSize < (21 * sizeof (CHAR16))) {
- return EFI_BUFFER_TOO_SMALL;
- }
-
- QuestionValue = &Question->CurrentValue;
- NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode;
-
- Value = (INT64)QuestionValue->Value.u64;
- switch (NumericOp->Flags & EFI_IFR_DISPLAY) {
- case EFI_IFR_DISPLAY_INT_DEC:
- switch (QuestionValue->Type) {
- case EFI_IFR_NUMERIC_SIZE_1:
- Value = (INT64)((INT8)QuestionValue->Value.u8);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_2:
- Value = (INT64)((INT16)QuestionValue->Value.u16);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_4:
- Value = (INT64)((INT32)QuestionValue->Value.u32);
- break;
-
- case EFI_IFR_NUMERIC_SIZE_8:
- default:
- break;
- }
-
- if (Value < 0) {
- Value = -Value;
- Format = L"-%ld";
- } else {
- Format = L"%ld";
- }
-
- break;
-
- case EFI_IFR_DISPLAY_UINT_DEC:
- Format = L"%ld";
- break;
-
- case EFI_IFR_DISPLAY_UINT_HEX:
- Format = L"%lx";
- break;
-
- default:
- return EFI_UNSUPPORTED;
- }
-
- UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
-
- return EFI_SUCCESS;
-}
-
-/**
- Draw a pop up windows based on the dimension, number of lines and
- strings specified.
-
- @param RequestedWidth The width of the pop-up.
- @param NumberOfLines The number of lines.
- @param Marker The variable argument list for the list of string to be printed.
-
-**/
-VOID
-CreateSharedPopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- IN VA_LIST Marker
- )
-{
- UINTN Index;
- UINTN Count;
- CHAR16 Character;
- UINTN Start;
- UINTN End;
- UINTN Top;
- UINTN Bottom;
- CHAR16 *String;
- UINTN DimensionsWidth;
- UINTN DimensionsHeight;
-
- DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
- DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
-
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
-
- if ((RequestedWidth + 2) > DimensionsWidth) {
- RequestedWidth = DimensionsWidth - 2;
- }
-
- //
- // Subtract the PopUp width from total Columns, allow for one space extra on
- // each end plus a border.
- //
- Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;
- End = Start + RequestedWidth + 1;
-
- Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;
- Bottom = Top + NumberOfLines + 2;
-
- Character = BOXDRAW_DOWN_RIGHT;
- PrintCharAt (Start, Top, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = Start; Index + 2 < End; Index++) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- Character = BOXDRAW_VERTICAL;
-
- Count = 0;
- for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
- String = VA_ARG (Marker, CHAR16 *);
-
- //
- // This will clear the background of the line - we never know who might have been
- // here before us. This differs from the next clear in that it used the non-reverse
- // video for normal printing.
- //
- if (GetStringWidth (String) / 2 > 1) {
- ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
- }
-
- //
- // Passing in a space results in the assumption that this is where typing will occur
- //
- if (String[0] == L' ') {
- ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());
- }
-
- //
- // Passing in a NULL results in a blank space
- //
- if (String[0] == CHAR_NULL) {
- ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
- }
-
- PrintStringAt (
- ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,
- Index + 1,
- String
- );
- gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
- PrintCharAt (Start, Index + 1, Character);
- PrintCharAt (End - 1, Index + 1, Character);
- }
-
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (Start, Bottom - 1, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = Start; Index + 2 < End; Index++) {
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
- }
-
- Character = BOXDRAW_UP_LEFT;
- PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
-}
-
-/**
- Draw a pop up windows based on the dimension, number of lines and
- strings specified.
-
- @param RequestedWidth The width of the pop-up.
- @param NumberOfLines The number of lines.
- @param ... A series of text strings that displayed in the pop-up.
-
-**/
-VOID
-EFIAPI
-CreateMultiStringPopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- ...
- )
-{
- VA_LIST Marker;
-
- VA_START (Marker, NumberOfLines);
-
- CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);
-
- VA_END (Marker);
-}
-
-/**
- Process nothing.
-
- @param Event The Event need to be process
- @param Context The context of the event.
-
-**/
-VOID
-EFIAPI
-EmptyEventProcess (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
-}
-
-/**
- Process for the refresh interval statement.
-
- @param Event The Event need to be process
- @param Context The context of the event.
-
-**/
-VOID
-EFIAPI
-RefreshTimeOutProcess (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- WARNING_IF_CONTEXT *EventInfo;
- CHAR16 TimeOutString[MAX_TIME_OUT_LEN];
-
- EventInfo = (WARNING_IF_CONTEXT *)Context;
-
- if (*(EventInfo->TimeOut) == 0) {
- gBS->CloseEvent (Event);
-
- gBS->SignalEvent (EventInfo->SyncEvent);
- return;
- }
-
- UnicodeSPrint (TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));
-
- CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL);
-
- *(EventInfo->TimeOut) -= 1;
-}
-
-/**
- Display error message for invalid password.
-
-**/
-VOID
-PasswordInvalid (
- VOID
- )
-{
- EFI_INPUT_KEY Key;
-
- //
- // Invalid password, prompt error message
- //
- do {
- CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-}
-
-/**
- Process password op code.
-
- @param MenuOption The menu for current password op code.
-
- @retval EFI_SUCCESS Question Option process success.
- @retval Other Question Option process fail.
-
-**/
-EFI_STATUS
-PasswordProcess (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- CHAR16 *StringPtr;
- CHAR16 *TempString;
- UINTN Maximum;
- EFI_STATUS Status;
- EFI_IFR_PASSWORD *PasswordInfo;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- EFI_INPUT_KEY Key;
-
- Question = MenuOption->ThisTag;
- PasswordInfo = (EFI_IFR_PASSWORD *)Question->OpCode;
- Maximum = PasswordInfo->MaxSize;
- Status = EFI_SUCCESS;
-
- StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
- ASSERT (StringPtr);
-
- //
- // Use a NULL password to test whether old password is required
- //
- *StringPtr = 0;
- Status = Question->PasswordCheck (gFormData, Question, StringPtr);
- if ((Status == EFI_NOT_AVAILABLE_YET) || (Status == EFI_UNSUPPORTED)) {
- //
- // Password can't be set now.
- //
- if (Status == EFI_UNSUPPORTED) {
- do {
- CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
- }
-
- FreePool (StringPtr);
- return EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status)) {
- //
- // Old password exist, ask user for the old password
- //
- Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
- if (EFI_ERROR (Status)) {
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- FreePool (StringPtr);
- return Status;
- }
-
- //
- // Check user input old password
- //
- Status = Question->PasswordCheck (gFormData, Question, StringPtr);
- if (EFI_ERROR (Status)) {
- if (Status == EFI_NOT_READY) {
- //
- // Typed in old password incorrect
- //
- PasswordInvalid ();
- } else {
- Status = EFI_SUCCESS;
- }
-
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- FreePool (StringPtr);
- return Status;
- }
- }
-
- //
- // Ask for new password
- //
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
- if (EFI_ERROR (Status)) {
- //
- // Reset state machine for password
- //
- Question->PasswordCheck (gFormData, Question, NULL);
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- FreePool (StringPtr);
- return Status;
- }
-
- //
- // Confirm new password
- //
- TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
- ASSERT (TempString);
- Status = ReadString (MenuOption, gConfirmPassword, TempString);
- if (EFI_ERROR (Status)) {
- //
- // Reset state machine for password
- //
- Question->PasswordCheck (gFormData, Question, NULL);
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
- FreePool (StringPtr);
- FreePool (TempString);
- return Status;
- }
-
- //
- // Compare two typed-in new passwords
- //
- if (StrCmp (StringPtr, TempString) == 0) {
- gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
- gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
- gUserInput->InputValue.Type = Question->CurrentValue.Type;
- gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
-
- Status = EFI_SUCCESS;
- } else {
- //
- // Reset state machine for password
- //
- Question->PasswordCheck (gFormData, Question, NULL);
-
- //
- // Two password mismatch, prompt error message
- //
- do {
- CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- Status = EFI_INVALID_PARAMETER;
- }
-
- ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
- ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
- FreePool (TempString);
- FreePool (StringPtr);
-
- return Status;
-}
-
-/**
- Print some debug message about mismatched menu info.
-
- @param MenuOption The MenuOption for this Question.
-
-**/
-VOID
-PrintMismatchMenuInfo (
- IN UI_MENU_OPTION *MenuOption
- )
-{
- CHAR16 *FormTitleStr;
- CHAR16 *FormSetTitleStr;
- CHAR16 *OneOfOptionStr;
- CHAR16 *QuestionName;
- LIST_ENTRY *Link;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- EFI_IFR_ORDERED_LIST *OrderList;
- UINT8 Index;
- EFI_HII_VALUE HiiValue;
- EFI_HII_VALUE *QuestionValue;
- DISPLAY_QUESTION_OPTION *Option;
- UINT8 *ValueArray;
- UINT8 ValueType;
- EFI_IFR_FORM_SET *FormsetBuffer;
- UINTN FormsetBufferSize;
-
- Question = MenuOption->ThisTag;
-
- if (!EFI_ERROR (HiiGetFormSetFromHiiHandle (gFormData->HiiHandle, &FormsetBuffer, &FormsetBufferSize))) {
- FormSetTitleStr = GetToken (FormsetBuffer->FormSetTitle, gFormData->HiiHandle);
- FormTitleStr = GetToken (gFormData->FormTitle, gFormData->HiiHandle);
-
- DEBUG ((DEBUG_ERROR, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName, &gFormData->FormSetGuid, FormSetTitleStr));
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName, gFormData->FormId, FormTitleStr));
- }
-
- if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
- QuestionName = GetToken (((EFI_IFR_ORDERED_LIST *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);
- Link = GetFirstNode (&Question->OptionListHead);
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- ValueType = Option->OptionOpCode->Type;
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName));
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName, QuestionName));
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName));
-
- OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
- for (Index = 0; Index < OrderList->MaxContainers; Index++) {
- ValueArray = Question->CurrentValue.Buffer;
- HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
- DEBUG ((DEBUG_ERROR, " Value[%d] =%ld.\n", Index, HiiValue.Value.u64));
- }
- } else if (Question->OpCode->OpCode == EFI_IFR_ONE_OF_OP) {
- QuestionName = GetToken (((EFI_IFR_ONE_OF *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);
- QuestionValue = &Question->CurrentValue;
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName));
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName, QuestionName));
- switch (QuestionValue->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_64:
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %ld.\n", gEfiCallerBaseName, QuestionValue->Value.u64));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u32));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u16));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_8:
- DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u8));
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- Index = 0;
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- OneOfOptionStr = GetToken (Option->OptionOpCode->Option, gFormData->HiiHandle);
- switch (Option->OptionOpCode->Type) {
- case EFI_IFR_TYPE_NUM_SIZE_64:
- DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u64, OneOfOptionStr));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_32:
- DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u32, OneOfOptionStr));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_16:
- DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u16, OneOfOptionStr));
- break;
-
- case EFI_IFR_TYPE_NUM_SIZE_8:
- DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u8, OneOfOptionStr));
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-
- Link = GetNextNode (&Question->OptionListHead, Link);
- Index++;
- }
-}
-
-/**
- Process a Question's Option (whether selected or un-selected).
-
- @param MenuOption The MenuOption for this Question.
- @param Selected TRUE: if Question is selected.
- @param OptionString Pointer of the Option String to be displayed.
- @param SkipErrorValue Whether need to return when value without option for it.
-
- @retval EFI_SUCCESS Question Option process success.
- @retval Other Question Option process fail.
-
-**/
-EFI_STATUS
-ProcessOptions (
- IN UI_MENU_OPTION *MenuOption,
- IN BOOLEAN Selected,
- OUT CHAR16 **OptionString,
- IN BOOLEAN SkipErrorValue
- )
-{
- EFI_STATUS Status;
- CHAR16 *StringPtr;
- UINTN Index;
- FORM_DISPLAY_ENGINE_STATEMENT *Question;
- CHAR16 FormattedNumber[21];
- UINT16 Number;
- CHAR16 Character[2];
- EFI_INPUT_KEY Key;
- UINTN BufferSize;
- DISPLAY_QUESTION_OPTION *OneOfOption;
- LIST_ENTRY *Link;
- EFI_HII_VALUE HiiValue;
- EFI_HII_VALUE *QuestionValue;
- DISPLAY_QUESTION_OPTION *Option;
- UINTN Index2;
- UINT8 *ValueArray;
- UINT8 ValueType;
- EFI_IFR_ORDERED_LIST *OrderList;
- BOOLEAN ValueInvalid;
- UINTN MaxLen;
-
- Status = EFI_SUCCESS;
-
- StringPtr = NULL;
- Character[1] = L'\0';
- *OptionString = NULL;
- ValueInvalid = FALSE;
-
- ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
- BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
-
- Question = MenuOption->ThisTag;
- QuestionValue = &Question->CurrentValue;
-
- switch (Question->OpCode->OpCode) {
- case EFI_IFR_ORDERED_LIST_OP:
-
- //
- // Check whether there are Options of this OrderedList
- //
- if (IsListEmpty (&Question->OptionListHead)) {
- break;
- }
-
- OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
-
- Link = GetFirstNode (&Question->OptionListHead);
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
-
- ValueType = OneOfOption->OptionOpCode->Type;
- ValueArray = Question->CurrentValue.Buffer;
-
- if (Selected) {
- //
- // Go ask for input
- //
- Status = GetSelectionInputPopUp (MenuOption);
- } else {
- //
- // We now know how many strings we will have, so we can allocate the
- // space required for the array or strings.
- //
- MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
- *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
- ASSERT (*OptionString);
-
- HiiValue.Type = ValueType;
- HiiValue.Value.u64 = 0;
- for (Index = 0; Index < OrderList->MaxContainers; Index++) {
- HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
- if (HiiValue.Value.u64 == 0) {
- //
- // Values for the options in ordered lists should never be a 0
- //
- break;
- }
-
- OneOfOption = ValueToOption (Question, &HiiValue);
- if (OneOfOption == NULL) {
- //
- // Print debug msg for the mistach menu.
- //
- PrintMismatchMenuInfo (MenuOption);
-
- if (SkipErrorValue) {
- //
- // Just try to get the option string, skip the value which not has option.
- //
- continue;
- }
-
- //
- // Show error message
- //
- do {
- CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- //
- // The initial value of the orderedlist is invalid, force to be valid value
- // Exit current DisplayForm with new value.
- //
- gUserInput->SelectedStatement = Question;
- gMisMatch = TRUE;
- ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
- ASSERT (ValueArray != NULL);
- gUserInput->InputValue.Buffer = ValueArray;
- gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
- gUserInput->InputValue.Type = Question->CurrentValue.Type;
-
- Link = GetFirstNode (&Question->OptionListHead);
- Index2 = 0;
- while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
- SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
- Index2++;
- }
-
- SetArrayData (ValueArray, ValueType, Index2, 0);
-
- FreePool (*OptionString);
- *OptionString = NULL;
- return EFI_NOT_FOUND;
- }
-
- Character[0] = LEFT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
- StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
- ASSERT (StringPtr != NULL);
- NewStrCat (OptionString[0], MaxLen, StringPtr);
- Character[0] = RIGHT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
- Character[0] = CHAR_CARRIAGE_RETURN;
- NewStrCat (OptionString[0], MaxLen, Character);
- FreePool (StringPtr);
- }
-
- //
- // If valid option more than the max container, skip these options.
- //
- if (Index >= OrderList->MaxContainers) {
- break;
- }
-
- //
- // Search the other options, try to find the one not in the container.
- //
- Link = GetFirstNode (&Question->OptionListHead);
- while (!IsNull (&Question->OptionListHead, Link)) {
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- Link = GetNextNode (&Question->OptionListHead, Link);
-
- if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
- continue;
- }
-
- //
- // Print debug msg for the mistach menu.
- //
- PrintMismatchMenuInfo (MenuOption);
-
- if (SkipErrorValue) {
- //
- // Not report error, just get the correct option string info.
- //
- Character[0] = LEFT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
- StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
- ASSERT (StringPtr != NULL);
- NewStrCat (OptionString[0], MaxLen, StringPtr);
- Character[0] = RIGHT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
- Character[0] = CHAR_CARRIAGE_RETURN;
- NewStrCat (OptionString[0], MaxLen, Character);
- FreePool (StringPtr);
-
- continue;
- }
-
- if (!ValueInvalid) {
- ValueInvalid = TRUE;
- //
- // Show error message
- //
- do {
- CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- //
- // The initial value of the orderedlist is invalid, force to be valid value
- // Exit current DisplayForm with new value.
- //
- gUserInput->SelectedStatement = Question;
- gMisMatch = TRUE;
- ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
- ASSERT (ValueArray != NULL);
- gUserInput->InputValue.Buffer = ValueArray;
- gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
- gUserInput->InputValue.Type = Question->CurrentValue.Type;
- }
-
- SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
- }
-
- if (ValueInvalid) {
- FreePool (*OptionString);
- *OptionString = NULL;
- return EFI_NOT_FOUND;
- }
- }
-
- break;
-
- case EFI_IFR_ONE_OF_OP:
- //
- // Check whether there are Options of this OneOf
- //
- if (IsListEmpty (&Question->OptionListHead)) {
- break;
- }
-
- if (Selected) {
- //
- // Go ask for input
- //
- Status = GetSelectionInputPopUp (MenuOption);
- } else {
- MaxLen = BufferSize / sizeof (CHAR16);
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- OneOfOption = ValueToOption (Question, QuestionValue);
- if (OneOfOption == NULL) {
- //
- // Print debug msg for the mistach menu.
- //
- PrintMismatchMenuInfo (MenuOption);
-
- if (SkipErrorValue) {
- //
- // Not report error, just get the correct option string info.
- //
- Link = GetFirstNode (&Question->OptionListHead);
- OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
- } else {
- //
- // Show error message
- //
- do {
- CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- //
- // Force the Question value to be valid
- // Exit current DisplayForm with new value.
- //
- Link = GetFirstNode (&Question->OptionListHead);
- Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
-
- gUserInput->InputValue.Type = Option->OptionOpCode->Type;
- switch (gUserInput->InputValue.Type) {
- case EFI_IFR_TYPE_NUM_SIZE_8:
- gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
- break;
- case EFI_IFR_TYPE_NUM_SIZE_16:
- CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
- break;
- case EFI_IFR_TYPE_NUM_SIZE_32:
- CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
- break;
- case EFI_IFR_TYPE_NUM_SIZE_64:
- CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
- break;
- default:
- ASSERT (FALSE);
- break;
- }
-
- gUserInput->SelectedStatement = Question;
- gMisMatch = TRUE;
- FreePool (*OptionString);
- *OptionString = NULL;
- return EFI_NOT_FOUND;
- }
- }
-
- Character[0] = LEFT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
- StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
- ASSERT (StringPtr != NULL);
- NewStrCat (OptionString[0], MaxLen, StringPtr);
- Character[0] = RIGHT_ONEOF_DELIMITER;
- NewStrCat (OptionString[0], MaxLen, Character);
-
- FreePool (StringPtr);
- }
-
- break;
-
- case EFI_IFR_CHECKBOX_OP:
- if (Selected) {
- //
- // Since this is a BOOLEAN operation, flip it upon selection
- //
- gUserInput->InputValue.Type = QuestionValue->Type;
- gUserInput->InputValue.Value.b = (BOOLEAN)(QuestionValue->Value.b ? FALSE : TRUE);
-
- //
- // Perform inconsistent check
- //
- return EFI_SUCCESS;
- } else {
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
-
- if (QuestionValue->Value.b) {
- *(OptionString[0] + 1) = CHECK_ON;
- } else {
- *(OptionString[0] + 1) = CHECK_OFF;
- }
-
- *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
- }
-
- break;
-
- case EFI_IFR_NUMERIC_OP:
- if (Selected) {
- //
- // Go ask for input
- //
- Status = GetNumericInput (MenuOption);
- } else {
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- *OptionString[0] = LEFT_NUMERIC_DELIMITER;
-
- //
- // Formatted print
- //
- PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
- Number = (UINT16)GetStringWidth (FormattedNumber);
- CopyMem (OptionString[0] + 1, FormattedNumber, Number);
-
- *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
- }
-
- break;
-
- case EFI_IFR_DATE_OP:
- if (Selected) {
- //
- // This is similar to numerics
- //
- Status = GetNumericInput (MenuOption);
- } else {
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- switch (MenuOption->Sequence) {
- case 0:
- *OptionString[0] = LEFT_NUMERIC_DELIMITER;
- if (QuestionValue->Value.date.Month == 0xff) {
- UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
- } else {
- UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
- }
-
- *(OptionString[0] + 3) = DATE_SEPARATOR;
- break;
-
- case 1:
- SetUnicodeMem (OptionString[0], 4, L' ');
- if (QuestionValue->Value.date.Day == 0xff) {
- UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
- } else {
- UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
- }
-
- *(OptionString[0] + 6) = DATE_SEPARATOR;
- break;
-
- case 2:
- SetUnicodeMem (OptionString[0], 7, L' ');
- if (QuestionValue->Value.date.Year == 0xff) {
- UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
- } else {
- UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
- }
-
- *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
- break;
- }
- }
-
- break;
-
- case EFI_IFR_TIME_OP:
- if (Selected) {
- //
- // This is similar to numerics
- //
- Status = GetNumericInput (MenuOption);
- } else {
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- switch (MenuOption->Sequence) {
- case 0:
- *OptionString[0] = LEFT_NUMERIC_DELIMITER;
- if (QuestionValue->Value.time.Hour == 0xff) {
- UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
- } else {
- UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
- }
-
- *(OptionString[0] + 3) = TIME_SEPARATOR;
- break;
-
- case 1:
- SetUnicodeMem (OptionString[0], 4, L' ');
- if (QuestionValue->Value.time.Minute == 0xff) {
- UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
- } else {
- UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
- }
-
- *(OptionString[0] + 6) = TIME_SEPARATOR;
- break;
-
- case 2:
- SetUnicodeMem (OptionString[0], 7, L' ');
- if (QuestionValue->Value.time.Second == 0xff) {
- UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
- } else {
- UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
- }
-
- *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
- break;
- }
- }
-
- break;
-
- case EFI_IFR_STRING_OP:
- if (Selected) {
- StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
- ASSERT (StringPtr);
- CopyMem (StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
-
- Status = ReadString (MenuOption, gPromptForData, StringPtr);
- if (EFI_ERROR (Status)) {
- FreePool (StringPtr);
- return Status;
- }
-
- gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
- gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
- gUserInput->InputValue.Type = Question->CurrentValue.Type;
- gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
- FreePool (StringPtr);
- return EFI_SUCCESS;
- } else {
- *OptionString = AllocateZeroPool (BufferSize);
- ASSERT (*OptionString);
-
- if (((CHAR16 *)Question->CurrentValue.Buffer)[0] == 0x0000) {
- *(OptionString[0]) = '_';
- } else {
- if (Question->CurrentValue.BufferLen < BufferSize) {
- BufferSize = Question->CurrentValue.BufferLen;
- }
-
- CopyMem (OptionString[0], (CHAR16 *)Question->CurrentValue.Buffer, BufferSize);
- }
- }
-
- break;
-
- case EFI_IFR_PASSWORD_OP:
- if (Selected) {
- Status = PasswordProcess (MenuOption);
- }
-
- break;
-
- default:
- break;
- }
-
- return Status;
-}
-
-/**
- Process the help string: Split StringPtr to several lines of strings stored in
- FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
-
- @param StringPtr The entire help string.
- @param FormattedString The oupput formatted string.
- @param EachLineWidth The max string length of each line in the formatted string.
- @param RowCount TRUE: if Question is selected.
-
-**/
-UINTN
-ProcessHelpString (
- IN CHAR16 *StringPtr,
- OUT CHAR16 **FormattedString,
- OUT UINT16 *EachLineWidth,
- IN UINTN RowCount
- )
-{
- UINTN Index;
- CHAR16 *OutputString;
- UINTN TotalRowNum;
- UINTN CheckedNum;
- UINT16 GlyphWidth;
- UINT16 LineWidth;
- UINT16 MaxStringLen;
- UINT16 StringLen;
-
- TotalRowNum = 0;
- CheckedNum = 0;
- GlyphWidth = 1;
- Index = 0;
- MaxStringLen = 0;
- StringLen = 0;
-
- //
- // Set default help string width.
- //
- LineWidth = (UINT16)(gHelpBlockWidth - 1);
-
- //
- // Get row number of the String.
- //
- while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
- if (StringLen > MaxStringLen) {
- MaxStringLen = StringLen;
- }
-
- TotalRowNum++;
- FreePool (OutputString);
- }
-
- *EachLineWidth = MaxStringLen;
-
- *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
- ASSERT (*FormattedString != NULL);
-
- //
- // Generate formatted help string array.
- //
- GlyphWidth = 1;
- Index = 0;
- while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
- CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
- CheckedNum++;
- FreePool (OutputString);
- }
-
- return TotalRowNum;
-}
+/** @file +Implementation for handling the User Interface option processing. + + +Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FormDisplay.h" + +#define MAX_TIME_OUT_LEN 0x10 + +/** + Concatenate a narrow string to another string. + + @param Destination The destination string. + @param DestMax The Max length of destination string. + @param Source The source string. The string to be concatenated. + to the end of Destination. + +**/ +VOID +NewStrCat ( + IN OUT CHAR16 *Destination, + IN UINTN DestMax, + IN CHAR16 *Source + ) +{ + UINTN Length; + + for (Length = 0; Destination[Length] != 0; Length++) { + } + + // + // We now have the length of the original string + // We can safely assume for now that we are concatenating a narrow value to this string. + // For instance, the string is "XYZ" and cat'ing ">" + // If this assumption changes, we need to make this routine a bit more complex + // + Destination[Length] = NARROW_CHAR; + Length++; + + StrCpyS (Destination + Length, DestMax - Length, Source); +} + +/** + Get UINT64 type value. + + @param Value Input Hii value. + + @retval UINT64 Return the UINT64 type value. + +**/ +UINT64 +HiiValueToUINT64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 RetVal; + + RetVal = 0; + + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + RetVal = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + RetVal = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + RetVal = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + RetVal = Value->Value.b; + break; + + case EFI_IFR_TYPE_DATE: + RetVal = *(UINT64 *)&Value->Value.date; + break; + + case EFI_IFR_TYPE_TIME: + RetVal = (*(UINT64 *)&Value->Value.time) & 0xffffff; + break; + + default: + RetVal = Value->Value.u64; + break; + } + + return RetVal; +} + +/** + Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type. + + EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to + EFI_IFR_TYPE_BUFFER when do the value compare. + + @param Value Expression value to compare on. + + @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. + @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. + +**/ +BOOLEAN +IsTypeInBuffer ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_BUFFER: + case EFI_IFR_TYPE_DATE: + case EFI_IFR_TYPE_TIME: + case EFI_IFR_TYPE_REF: + return TRUE; + + default: + return FALSE; + } +} + +/** + Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64 + + @param Value Expression value to compare on. + + @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. + @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. + +**/ +BOOLEAN +IsTypeInUINT64 ( + IN EFI_HII_VALUE *Value + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + case EFI_IFR_TYPE_BOOLEAN: + return TRUE; + + default: + return FALSE; + } +} + +/** + Return the buffer length and buffer pointer for this value. + + EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to + EFI_IFR_TYPE_BUFFER when do the value compare. + + @param Value Expression value to compare on. + @param Buf Return the buffer pointer. + @param BufLen Return the buffer length. + +**/ +VOID +GetBufAndLenForValue ( + IN EFI_HII_VALUE *Value, + OUT UINT8 **Buf, + OUT UINT16 *BufLen + ) +{ + switch (Value->Type) { + case EFI_IFR_TYPE_BUFFER: + *Buf = Value->Buffer; + *BufLen = Value->BufferLen; + break; + + case EFI_IFR_TYPE_DATE: + *Buf = (UINT8 *)(&Value->Value.date); + *BufLen = (UINT16)sizeof (EFI_HII_DATE); + break; + + case EFI_IFR_TYPE_TIME: + *Buf = (UINT8 *)(&Value->Value.time); + *BufLen = (UINT16)sizeof (EFI_HII_TIME); + break; + + case EFI_IFR_TYPE_REF: + *Buf = (UINT8 *)(&Value->Value.ref); + *BufLen = (UINT16)sizeof (EFI_HII_REF); + break; + + default: + *Buf = NULL; + *BufLen = 0; + } +} + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param Result Return value after compare. + retval 0 Two operators equal. + return Positive value if Value1 is greater than Value2. + retval Negative value if Value1 is less than Value2. + @param HiiHandle Only required for string compare. + + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. + +**/ +EFI_STATUS +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + OUT INTN *Result, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + UINTN Len; + UINT8 *Buf1; + UINT16 Buf1Len; + UINT8 *Buf2; + UINT16 Buf2Len; + + if ((Value1->Type == EFI_IFR_TYPE_STRING) && (Value2->Type == EFI_IFR_TYPE_STRING)) { + if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + *Result = 0; + return EFI_SUCCESS; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_NOT_FOUND; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + FreePool (Str1); + return EFI_NOT_FOUND; + } + + *Result = StrCmp (Str1, Str2); + + FreePool (Str1); + FreePool (Str2); + + return EFI_SUCCESS; + } + + // + // Take types(date, time, ref, buffer) as buffer + // + if (IsTypeInBuffer (Value1) && IsTypeInBuffer (Value2)) { + GetBufAndLenForValue (Value1, &Buf1, &Buf1Len); + GetBufAndLenForValue (Value2, &Buf2, &Buf2Len); + + Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len; + *Result = CompareMem (Buf1, Buf2, Len); + if ((*Result == 0) && (Buf1Len != Buf2Len)) { + // + // In this case, means base on samll number buffer, the data is same + // So which value has more data, which value is bigger. + // + *Result = Buf1Len > Buf2Len ? 1 : -1; + } + + return EFI_SUCCESS; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + if (IsTypeInUINT64 (Value1) && IsTypeInUINT64 (Value2)) { + Temp64 = HiiValueToUINT64 (Value1) - HiiValueToUINT64 (Value2); + if (Temp64 > 0) { + *Result = 1; + } else if (Temp64 < 0) { + *Result = -1; + } else { + *Result = 0; + } + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +DISPLAY_QUESTION_OPTION * +ValueToOption ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +{ + LIST_ENTRY *Link; + DISPLAY_QUESTION_OPTION *Option; + INTN Result; + EFI_HII_VALUE Value; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + ZeroMem (&Value, sizeof (EFI_HII_VALUE)); + Value.Type = Option->OptionOpCode->Type; + CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); + + if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { + return Option; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + return NULL; +} + +/** + Return data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +GetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ) +{ + UINT64 Data; + + ASSERT (Array != NULL); + + Data = 0; + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data = (UINT64)*(((UINT8 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Data = (UINT64)*(((UINT16 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Data = (UINT64)*(((UINT32 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Data = (UINT64)*(((UINT64 *)Array) + Index); + break; + + default: + break; + } + + return Data; +} + +/** + Set value of a data element in an Array by its Index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +SetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ) +{ + ASSERT (Array != NULL); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + *(((UINT8 *)Array) + Index) = (UINT8)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + *(((UINT16 *)Array) + Index) = (UINT16)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + *(((UINT32 *)Array) + Index) = (UINT32)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + *(((UINT64 *)Array) + Index) = (UINT64)Value; + break; + + default: + break; + } +} + +/** + Check whether this value already in the array, if yes, return the index. + + @param Array The data array. + @param Type Type of the data in this array. + @param Value The value to be find. + @param Index The index in the array which has same value with Value. + + @retval TRUE Found the value in the array. + @retval FALSE Not found the value. + +**/ +BOOLEAN +FindArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINT64 Value, + OUT UINTN *Index OPTIONAL + ) +{ + UINTN Count; + UINT64 TmpValue; + UINT64 ValueComp; + + ASSERT (Array != NULL); + + Count = 0; + TmpValue = 0; + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + ValueComp = (UINT8)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + ValueComp = (UINT16)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + ValueComp = (UINT32)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + ValueComp = (UINT64)Value; + break; + + default: + ValueComp = 0; + break; + } + + while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) { + if (ValueComp == TmpValue) { + if (Index != NULL) { + *Index = Count; + } + + return TRUE; + } + + Count++; + } + + return FALSE; +} + +/** + Print Question Value according to it's storage width and display attributes. + + @param Question The Question to be printed. + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_DISPLAY_ENGINE_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +{ + INT64 Value; + CHAR16 *Format; + EFI_HII_VALUE *QuestionValue; + EFI_IFR_NUMERIC *NumericOp; + + if (BufferSize < (21 * sizeof (CHAR16))) { + return EFI_BUFFER_TOO_SMALL; + } + + QuestionValue = &Question->CurrentValue; + NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode; + + Value = (INT64)QuestionValue->Value.u64; + switch (NumericOp->Flags & EFI_IFR_DISPLAY) { + case EFI_IFR_DISPLAY_INT_DEC: + switch (QuestionValue->Type) { + case EFI_IFR_NUMERIC_SIZE_1: + Value = (INT64)((INT8)QuestionValue->Value.u8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Value = (INT64)((INT16)QuestionValue->Value.u16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Value = (INT64)((INT32)QuestionValue->Value.u32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + default: + break; + } + + if (Value < 0) { + Value = -Value; + Format = L"-%ld"; + } else { + Format = L"%ld"; + } + + break; + + case EFI_IFR_DISPLAY_UINT_DEC: + Format = L"%ld"; + break; + + case EFI_IFR_DISPLAY_UINT_HEX: + Format = L"%lx"; + break; + + default: + return EFI_UNSUPPORTED; + } + + UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); + + return EFI_SUCCESS; +} + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param Marker The variable argument list for the list of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN VA_LIST Marker + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; + DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; + + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + + if ((RequestedWidth + 2) > DimensionsWidth) { + RequestedWidth = DimensionsWidth - 2; + } + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + Character = BOXDRAW_VERTICAL; + + Count = 0; + for (Index = Top; Index + 2 < Bottom; Index++, Count++) { + String = VA_ARG (Marker, CHAR16 *); + + // + // This will clear the background of the line - we never know who might have been + // here before us. This differs from the next clear in that it used the non-reverse + // video for normal printing. + // + if (GetStringWidth (String) / 2 > 1) { + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + } + + // + // Passing in a space results in the assumption that this is where typing will occur + // + if (String[0] == L' ') { + ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ()); + } + + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintCharAt ((UINTN)-1, (UINTN)-1, Character); +} + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +EFIAPI +CreateMultiStringPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + ... + ) +{ + VA_LIST Marker; + + VA_START (Marker, NumberOfLines); + + CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker); + + VA_END (Marker); +} + +/** + Process nothing. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +EmptyEventProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + Process for the refresh interval statement. + + @param Event The Event need to be process + @param Context The context of the event. + +**/ +VOID +EFIAPI +RefreshTimeOutProcess ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + WARNING_IF_CONTEXT *EventInfo; + CHAR16 TimeOutString[MAX_TIME_OUT_LEN]; + + EventInfo = (WARNING_IF_CONTEXT *)Context; + + if (*(EventInfo->TimeOut) == 0) { + gBS->CloseEvent (Event); + + gBS->SignalEvent (EventInfo->SyncEvent); + return; + } + + UnicodeSPrint (TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut)); + + CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL); + + *(EventInfo->TimeOut) -= 1; +} + +/** + Display error message for invalid password. + +**/ +VOID +PasswordInvalid ( + VOID + ) +{ + EFI_INPUT_KEY Key; + + // + // Invalid password, prompt error message + // + do { + CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); +} + +/** + Process password op code. + + @param MenuOption The menu for current password op code. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +PasswordProcess ( + IN UI_MENU_OPTION *MenuOption + ) +{ + CHAR16 *StringPtr; + CHAR16 *TempString; + UINTN Maximum; + EFI_STATUS Status; + EFI_IFR_PASSWORD *PasswordInfo; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + EFI_INPUT_KEY Key; + + Question = MenuOption->ThisTag; + PasswordInfo = (EFI_IFR_PASSWORD *)Question->OpCode; + Maximum = PasswordInfo->MaxSize; + Status = EFI_SUCCESS; + + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + // + // Use a NULL password to test whether old password is required + // + *StringPtr = 0; + Status = Question->PasswordCheck (gFormData, Question, StringPtr); + if ((Status == EFI_NOT_AVAILABLE_YET) || (Status == EFI_UNSUPPORTED)) { + // + // Password can't be set now. + // + if (Status == EFI_UNSUPPORTED) { + do { + CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + FreePool (StringPtr); + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // Old password exist, ask user for the old password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + FreePool (StringPtr); + return Status; + } + + // + // Check user input old password + // + Status = Question->PasswordCheck (gFormData, Question, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_READY) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + } else { + Status = EFI_SUCCESS; + } + + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + FreePool (StringPtr); + return Status; + } + } + + // + // Ask for new password + // + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); + if (EFI_ERROR (Status)) { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + FreePool (StringPtr); + return Status; + } + + // + // Confirm new password + // + TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (TempString); + Status = ReadString (MenuOption, gConfirmPassword, TempString); + if (EFI_ERROR (Status)) { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16)); + FreePool (StringPtr); + FreePool (TempString); + return Status; + } + + // + // Compare two typed-in new passwords + // + if (StrCmp (StringPtr, TempString) == 0) { + gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); + + Status = EFI_SUCCESS; + } else { + // + // Reset state machine for password + // + Question->PasswordCheck (gFormData, Question, NULL); + + // + // Two password mismatch, prompt error message + // + do { + CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + Status = EFI_INVALID_PARAMETER; + } + + ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16)); + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + FreePool (TempString); + FreePool (StringPtr); + + return Status; +} + +/** + Print some debug message about mismatched menu info. + + @param MenuOption The MenuOption for this Question. + +**/ +VOID +PrintMismatchMenuInfo ( + IN UI_MENU_OPTION *MenuOption + ) +{ + CHAR16 *FormTitleStr; + CHAR16 *FormSetTitleStr; + CHAR16 *OneOfOptionStr; + CHAR16 *QuestionName; + LIST_ENTRY *Link; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + EFI_IFR_ORDERED_LIST *OrderList; + UINT8 Index; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *QuestionValue; + DISPLAY_QUESTION_OPTION *Option; + UINT8 *ValueArray; + UINT8 ValueType; + EFI_IFR_FORM_SET *FormsetBuffer; + UINTN FormsetBufferSize; + + Question = MenuOption->ThisTag; + + if (!EFI_ERROR (HiiGetFormSetFromHiiHandle (gFormData->HiiHandle, &FormsetBuffer, &FormsetBufferSize))) { + FormSetTitleStr = GetToken (FormsetBuffer->FormSetTitle, gFormData->HiiHandle); + FormTitleStr = GetToken (gFormData->FormTitle, gFormData->HiiHandle); + + DEBUG ((DEBUG_ERROR, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName, &gFormData->FormSetGuid, FormSetTitleStr)); + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName, gFormData->FormId, FormTitleStr)); + } + + if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) { + QuestionName = GetToken (((EFI_IFR_ORDERED_LIST *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle); + Link = GetFirstNode (&Question->OptionListHead); + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + ValueType = Option->OptionOpCode->Type; + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName)); + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName, QuestionName)); + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName)); + + OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + ValueArray = Question->CurrentValue.Buffer; + HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); + DEBUG ((DEBUG_ERROR, " Value[%d] =%ld.\n", Index, HiiValue.Value.u64)); + } + } else if (Question->OpCode->OpCode == EFI_IFR_ONE_OF_OP) { + QuestionName = GetToken (((EFI_IFR_ONE_OF *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle); + QuestionValue = &Question->CurrentValue; + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName)); + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName, QuestionName)); + switch (QuestionValue->Type) { + case EFI_IFR_TYPE_NUM_SIZE_64: + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %ld.\n", gEfiCallerBaseName, QuestionValue->Value.u64)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u32)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u16)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_8: + DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u8)); + break; + + default: + ASSERT (FALSE); + break; + } + } + + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + OneOfOptionStr = GetToken (Option->OptionOpCode->Option, gFormData->HiiHandle); + switch (Option->OptionOpCode->Type) { + case EFI_IFR_TYPE_NUM_SIZE_64: + DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u64, OneOfOptionStr)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u32, OneOfOptionStr)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u16, OneOfOptionStr)); + break; + + case EFI_IFR_TYPE_NUM_SIZE_8: + DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u8, OneOfOptionStr)); + break; + + default: + ASSERT (FALSE); + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + Index++; + } +} + +/** + Process a Question's Option (whether selected or un-selected). + + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + @param SkipErrorValue Whether need to return when value without option for it. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString, + IN BOOLEAN SkipErrorValue + ) +{ + EFI_STATUS Status; + CHAR16 *StringPtr; + UINTN Index; + FORM_DISPLAY_ENGINE_STATEMENT *Question; + CHAR16 FormattedNumber[21]; + UINT16 Number; + CHAR16 Character[2]; + EFI_INPUT_KEY Key; + UINTN BufferSize; + DISPLAY_QUESTION_OPTION *OneOfOption; + LIST_ENTRY *Link; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *QuestionValue; + DISPLAY_QUESTION_OPTION *Option; + UINTN Index2; + UINT8 *ValueArray; + UINT8 ValueType; + EFI_IFR_ORDERED_LIST *OrderList; + BOOLEAN ValueInvalid; + UINTN MaxLen; + + Status = EFI_SUCCESS; + + StringPtr = NULL; + Character[1] = L'\0'; + *OptionString = NULL; + ValueInvalid = FALSE; + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow; + + Question = MenuOption->ThisTag; + QuestionValue = &Question->CurrentValue; + + switch (Question->OpCode->OpCode) { + case EFI_IFR_ORDERED_LIST_OP: + + // + // Check whether there are Options of this OrderedList + // + if (IsListEmpty (&Question->OptionListHead)) { + break; + } + + OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; + + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + ValueType = OneOfOption->OptionOpCode->Type; + ValueArray = Question->CurrentValue.Buffer; + + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (MenuOption); + } else { + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16); + *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + ASSERT (*OptionString); + + HiiValue.Type = ValueType; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < OrderList->MaxContainers; Index++) { + HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); + if (HiiValue.Value.u64 == 0) { + // + // Values for the options in ordered lists should never be a 0 + // + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + // + // Print debug msg for the mistach menu. + // + PrintMismatchMenuInfo (MenuOption); + + if (SkipErrorValue) { + // + // Just try to get the option string, skip the value which not has option. + // + continue; + } + + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // The initial value of the orderedlist is invalid, force to be valid value + // Exit current DisplayForm with new value. + // + gUserInput->SelectedStatement = Question; + gMisMatch = TRUE; + ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen); + ASSERT (ValueArray != NULL); + gUserInput->InputValue.Buffer = ValueArray; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + + Link = GetFirstNode (&Question->OptionListHead); + Index2 = 0; + while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) { + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64); + Index2++; + } + + SetArrayData (ValueArray, ValueType, Index2, 0); + + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], MaxLen, StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], MaxLen, Character); + FreePool (StringPtr); + } + + // + // If valid option more than the max container, skip these options. + // + if (Index >= OrderList->MaxContainers) { + break; + } + + // + // Search the other options, try to find the one not in the container. + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) { + continue; + } + + // + // Print debug msg for the mistach menu. + // + PrintMismatchMenuInfo (MenuOption); + + if (SkipErrorValue) { + // + // Not report error, just get the correct option string info. + // + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], MaxLen, StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], MaxLen, Character); + FreePool (StringPtr); + + continue; + } + + if (!ValueInvalid) { + ValueInvalid = TRUE; + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // The initial value of the orderedlist is invalid, force to be valid value + // Exit current DisplayForm with new value. + // + gUserInput->SelectedStatement = Question; + gMisMatch = TRUE; + ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer); + ASSERT (ValueArray != NULL); + gUserInput->InputValue.Buffer = ValueArray; + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + } + + SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64); + } + + if (ValueInvalid) { + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + } + + break; + + case EFI_IFR_ONE_OF_OP: + // + // Check whether there are Options of this OneOf + // + if (IsListEmpty (&Question->OptionListHead)) { + break; + } + + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (MenuOption); + } else { + MaxLen = BufferSize / sizeof (CHAR16); + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + OneOfOption = ValueToOption (Question, QuestionValue); + if (OneOfOption == NULL) { + // + // Print debug msg for the mistach menu. + // + PrintMismatchMenuInfo (MenuOption); + + if (SkipErrorValue) { + // + // Not report error, just get the correct option string info. + // + Link = GetFirstNode (&Question->OptionListHead); + OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + } else { + // + // Show error message + // + do { + CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + // + // Force the Question value to be valid + // Exit current DisplayForm with new value. + // + Link = GetFirstNode (&Question->OptionListHead); + Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); + + gUserInput->InputValue.Type = Option->OptionOpCode->Type; + switch (gUserInput->InputValue.Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8; + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16)); + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32)); + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64)); + break; + default: + ASSERT (FALSE); + break; + } + + gUserInput->SelectedStatement = Question; + gMisMatch = TRUE; + FreePool (*OptionString); + *OptionString = NULL; + return EFI_NOT_FOUND; + } + } + + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); + ASSERT (StringPtr != NULL); + NewStrCat (OptionString[0], MaxLen, StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], MaxLen, Character); + + FreePool (StringPtr); + } + + break; + + case EFI_IFR_CHECKBOX_OP: + if (Selected) { + // + // Since this is a BOOLEAN operation, flip it upon selection + // + gUserInput->InputValue.Type = QuestionValue->Type; + gUserInput->InputValue.Value.b = (BOOLEAN)(QuestionValue->Value.b ? FALSE : TRUE); + + // + // Perform inconsistent check + // + return EFI_SUCCESS; + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_CHECKBOX_DELIMITER; + + if (QuestionValue->Value.b) { + *(OptionString[0] + 1) = CHECK_ON; + } else { + *(OptionString[0] + 1) = CHECK_OFF; + } + + *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; + } + + break; + + case EFI_IFR_NUMERIC_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + // + // Formatted print + // + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + Number = (UINT16)GetStringWidth (FormattedNumber); + CopyMem (OptionString[0] + 1, FormattedNumber, Number); + + *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; + } + + break; + + case EFI_IFR_DATE_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + if (QuestionValue->Value.date.Month == 0xff) { + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); + } else { + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); + } + + *(OptionString[0] + 3) = DATE_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + if (QuestionValue->Value.date.Day == 0xff) { + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); + } else { + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); + } + + *(OptionString[0] + 6) = DATE_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + if (QuestionValue->Value.date.Year == 0xff) { + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????"); + } else { + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year); + } + + *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + + break; + + case EFI_IFR_TIME_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + if (QuestionValue->Value.time.Hour == 0xff) { + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); + } else { + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); + } + + *(OptionString[0] + 3) = TIME_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + if (QuestionValue->Value.time.Minute == 0xff) { + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); + } else { + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); + } + + *(OptionString[0] + 6) = TIME_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + if (QuestionValue->Value.time.Second == 0xff) { + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??"); + } else { + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); + } + + *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + + break; + + case EFI_IFR_STRING_OP: + if (Selected) { + StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16)); + ASSERT (StringPtr); + CopyMem (StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen); + + Status = ReadString (MenuOption, gPromptForData, StringPtr); + if (EFI_ERROR (Status)) { + FreePool (StringPtr); + return Status; + } + + gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); + gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; + gUserInput->InputValue.Type = Question->CurrentValue.Type; + gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); + FreePool (StringPtr); + return EFI_SUCCESS; + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + if (((CHAR16 *)Question->CurrentValue.Buffer)[0] == 0x0000) { + *(OptionString[0]) = '_'; + } else { + if (Question->CurrentValue.BufferLen < BufferSize) { + BufferSize = Question->CurrentValue.BufferLen; + } + + CopyMem (OptionString[0], (CHAR16 *)Question->CurrentValue.Buffer, BufferSize); + } + } + + break; + + case EFI_IFR_PASSWORD_OP: + if (Selected) { + Status = PasswordProcess (MenuOption); + } + + break; + + default: + break; + } + + return Status; +} + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param FormattedString The oupput formatted string. + @param EachLineWidth The max string length of each line in the formatted string. + @param RowCount TRUE: if Question is selected. + +**/ +UINTN +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + OUT UINT16 *EachLineWidth, + IN UINTN RowCount + ) +{ + UINTN Index; + CHAR16 *OutputString; + UINTN TotalRowNum; + UINTN CheckedNum; + UINT16 GlyphWidth; + UINT16 LineWidth; + UINT16 MaxStringLen; + UINT16 StringLen; + + TotalRowNum = 0; + CheckedNum = 0; + GlyphWidth = 1; + Index = 0; + MaxStringLen = 0; + StringLen = 0; + + // + // Set default help string width. + // + LineWidth = (UINT16)(gHelpBlockWidth - 1); + + // + // Get row number of the String. + // + while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { + if (StringLen > MaxStringLen) { + MaxStringLen = StringLen; + } + + TotalRowNum++; + FreePool (OutputString); + } + + *EachLineWidth = MaxStringLen; + + *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16)); + ASSERT (*FormattedString != NULL); + + // + // Generate formatted help string array. + // + GlyphWidth = 1; + Index = 0; + while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { + CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16)); + CheckedNum++; + FreePool (OutputString); + } + + return TotalRowNum; +} |
