diff options
Diffstat (limited to 'MdeModulePkg/Universal')
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf | 70 | ||||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c | 3200 | ||||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h | 580 | ||||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni | bin | 0 -> 8660 bytes | |||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c | 1531 | ||||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/Print.c | 54 | ||||
-rw-r--r-- | MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c | 1286 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Expression.c | 6 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Expression.h | 265 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c | 65 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c | 2425 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Setup.c | 2291 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Setup.h | 814 | ||||
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf | 28 |
14 files changed, 10434 insertions, 2181 deletions
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf new file mode 100644 index 0000000000..2170369d9e --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf @@ -0,0 +1,70 @@ +## @file
+# The DXE driver produces FORM BROWSER protocols defined in UEFI HII 2.1 specificatin.
+#
+# Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DisplayEngine
+ 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 IPF EBC
+#
+
+[Sources]
+ FormDisplayStr.uni
+ FormDisplay.c
+ FormDisplay.h
+ Print.c
+ ProcessOptions.c
+ InputHandler.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+ BaseLib
+ PrintLib
+ HiiLib
+ MemoryAllocationLib
+ CustomizedDisplayLib
+
+[Protocols]
+ gEdkiiFormDisplayEngineProtocolGuid
+ gEdkiiFormBrowserEx2ProtocolGuid
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## GUID
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES
+
+[BuildOptions]
+ MSFT:*_*_*_CC_FLAGS = /Od
+
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c new file mode 100644 index 0000000000..f6322293fc --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c @@ -0,0 +1,3200 @@ +/** @file
+Entry and initialization module for the browser.
+
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);
+
+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}
+};
+
+UINTN gSequence;
+EFI_SCREEN_DESCRIPTOR gStatementDimensions;
+EFI_SCREEN_DESCRIPTOR gOldStatementDimensions = {0};
+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};
+
+//
+// Browser Global Strings
+//
+CHAR16 *gFormNotFound;
+CHAR16 *gNoSubmitIf;
+CHAR16 *gBrwoserError;
+CHAR16 *gSaveFailed;
+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 gPromptBlockWidth;
+CHAR16 gOptionBlockWidth;
+CHAR16 gHelpBlockWidth;
+CHAR16 *mUnknownString;
+
+FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {
+ FORM_DISPLAY_DRIVER_SIGNATURE,
+ NULL,
+ {
+ FormDisplay,
+ ClearDisplayPage,
+ ConfirmDataChange
+ }
+};
+
+
+/**
+ 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
+ )
+{
+ mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);
+ gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), 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);
+ gBrwoserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);
+}
+
+/**
+ Free up the resource allocated for all strings required
+ by Setup Browser.
+
+**/
+VOID
+FreeDisplayStrings (
+ VOID
+ )
+{
+ FreePool (mUnknownString);
+ FreePool (gEmptyString);
+ FreePool (gSaveFailed);
+ FreePool (gPromptForData);
+ FreePool (gPromptForPassword);
+ FreePool (gPromptForNewPassword);
+ FreePool (gConfirmPassword);
+ FreePool (gConfirmError);
+ FreePool (gPassowordInvalid);
+ FreePool (gPressEnter);
+ FreePool (gMiniString);
+ FreePool (gOptionMismatch);
+ FreePool (gFormSuppress);
+ FreePool (gProtocolNotFound);
+ FreePool (gBrwoserError);
+ FreePool (gNoSubmitIf);
+ FreePool (gFormNotFound);
+}
+
+/**
+ 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 Statement The curent statement.
+
+ @return Returns the number of CHAR16 characters that is support.
+
+**/
+UINT16
+GetWidth (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement
+ )
+{
+ CHAR16 *String;
+ UINTN Size;
+ UINT16 Width;
+ EFI_IFR_TEXT *TestOp;
+
+ Size = 0;
+
+ //
+ // See if the second text parameter is really NULL
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ TestOp = (EFI_IFR_TEXT *) Statement->OpCode;
+ if (TestOp->TextTwo != 0) {
+ String = GetToken (TestOp->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))
+ ) {
+ Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);
+ } else {
+ Width = (UINT16) gPromptBlockWidth;
+ }
+
+ return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);
+}
+
+/**
+ 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 (((UINTN) (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;
+ CHAR16 *String;
+ 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);
+
+ String = GetToken (PromptId, gFormData->HiiHandle);
+ ASSERT (String != NULL);
+
+ Width = GetWidth (Statement);
+ for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&String[ArrayEntry]) != 0) {
+ NumberOfLines++;
+ }
+ FreePool (OutputString);
+ }
+
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ //
+ // Add three MenuOptions for Date/Time
+ // Data format : [01/02/2004] [11:22:33]
+ // Line number : 0 0 1 0 0 1
+ //
+ NumberOfLines = 0;
+ Count = 3;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
+ ASSERT (MenuOption);
+
+ MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
+ MenuOption->Description = String;
+ MenuOption->Handle = gFormData->HiiHandle;
+ MenuOption->ThisTag = Statement;
+ MenuOption->NestInStatement = NestIn;
+ MenuOption->EntryNumber = *MenuItemCount;
+
+ if (Index == 2) {
+ //
+ // Override LineNumber for the MenuOption in Date/Time sequence
+ //
+ MenuOption->Skip = 1;
+ } else {
+ MenuOption->Skip = NumberOfLines;
+ }
+ 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;
+ }
+ }
+
+ 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);
+
+ 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;
+ 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 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) {
+ 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.
+
+ @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 l
+ last menu showing at current form.
+
+**/
+INTN
+MoveToNextStatement (
+ IN BOOLEAN GoUp,
+ IN OUT LIST_ENTRY **CurrentPosition,
+ IN UINTN GapToTop
+ )
+{
+ INTN Distance;
+ LIST_ENTRY *Pos;
+ UI_MENU_OPTION *NextMenuOption;
+ UI_MENU_OPTION *PreMenuOption;
+
+ Distance = 0;
+ Pos = *CurrentPosition;
+ 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);
+ }
+
+ if (GoUp && (PreMenuOption != NextMenuOption)) {
+ //
+ // In this case, still can't find the selectable menu,
+ // return the last one in the showing form.
+ //
+ if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {
+ NextMenuOption = PreMenuOption;
+ break;
+ }
+
+ //
+ // Current Position doesn't need to be caculated when go up.
+ // Caculate distanct at first when go up
+ //
+ Distance += NextMenuOption->Skip;
+ }
+
+ if (IsSelectable (NextMenuOption)) {
+ break;
+ }
+
+ //
+ // Arrive at begin of the menu list.
+ //
+ if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {
+ Distance = -1;
+ break;
+ }
+
+ if (!GoUp) {
+ //
+ // In this case, still can't find the selectable menu,
+ // return the last one in the showing form.
+ //
+ if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {
+ NextMenuOption = PreMenuOption;
+ break;
+ }
+
+ Distance += NextMenuOption->Skip;
+ }
+
+ PreMenuOption = NextMenuOption;
+ Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
+ }
+
+ *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 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 INTN *SkipValue
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NewPos;
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN Index;
+ UI_MENU_OPTION *SavedMenuOption;
+ UINTN EndRow;
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
+
+ //
+ // If not has input highlight statement, just return the first one in this form.
+ //
+ if (FormData->HighLightedStatement == NULL) {
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *HighlightMenu = gMenuOption.ForwardLink;
+ if (!IsListEmpty (&gMenuOption)) {
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow);
+ }
+ *SkipValue = 0;
+ return;
+ }
+
+ //
+ // Now base on the input highlight menu to find the top menu in this page.
+ // Will base on the highlight menu show at the bottom to find the top menu.
+ //
+ NewPos = gMenuOption.ForwardLink;
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ while ((SavedMenuOption->ThisTag != FormData->HighLightedStatement) ||
+ (SavedMenuOption->Sequence != gSequence)) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+ ASSERT (SavedMenuOption->ThisTag == FormData->HighLightedStatement);
+
+ *HighlightMenu = NewPos;
+
+ AdjustDateAndTimePosition(FALSE, &NewPos);
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ UpdateOptionSkipLines (SavedMenuOption);
+
+ //
+ // If highlight opcode is date/time, keep the highlight row info not change.
+ //
+ if ((SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP || SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) &&
+ (gHighligthMenuInfo.QuestionId != 0) &&
+ (gHighligthMenuInfo.QuestionId == GetQuestionIdInfo(SavedMenuOption->ThisTag->OpCode))) {
+ //
+ // Still show the highlight menu before exit from display engine.
+ //
+ EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;
+ } else {
+ EndRow = BottomRow;
+ }
+
+ //
+ // Base on the selected menu will show at the bottome of next page,
+ // select the menu show at the top of the next page.
+ //
+ Link = NewPos;
+ for (Index = TopRow + SavedMenuOption->Skip; Index <= EndRow; ) {
+ Link = Link->BackLink;
+ //
+ // Already find the first menu in this form, means highlight menu
+ // will show in first page of this form.
+ //
+ if (Link == &gMenuOption) {
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *SkipValue = 0;
+ return;
+ }
+ SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
+ UpdateOptionSkipLines (SavedMenuOption);
+ Index += SavedMenuOption->Skip;
+ }
+
+ //
+ // Found the menu which will show at the top of the page.
+ //
+ if (Link == NewPos) {
+ //
+ // The menu can show more than one pages, just show the menu at the top of the page.
+ //
+ *SkipValue = 0;
+ *TopOfScreen = Link;
+ } else {
+ //
+ // Check whether need to skip some line for menu shows at the top of the page.
+ //
+ *SkipValue = Index - EndRow;
+ if (*SkipValue > 0 && *SkipValue < (INTN) SavedMenuOption->Skip) {
+ *TopOfScreen = Link;
+ } else {
+ *SkipValue = 0;
+ *TopOfScreen = Link->ForwardLink;
+ }
+ }
+}
+
+/**
+ 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
+ )
+{
+ INTN SkipValue;
+ INTN Difference;
+ UINTN DistanceValue;
+ UINTN Row;
+ UINTN Col;
+ UINTN TempRightCol;
+ UINTN Temp;
+ UINTN Temp2;
+ UINTN Temp3;
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN OriginalRow;
+ UINTN Index;
+ UINT16 Width;
+ CHAR16 *StringPtr;
+ CHAR16 *OptionString;
+ CHAR16 *OutputString;
+ 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_MENU_OPTION *PreviousMenuOption;
+ UI_CONTROL_FLAG ControlFlag;
+ UI_SCREEN_OPERATION ScreenOperation;
+ UINT16 DefaultId;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ UINTN ModalSkipColumn;
+ BROWSER_HOT_KEY *HotKey;
+ UINTN HelpPageIndex;
+ UINTN HelpPageCount;
+ UINTN RowCount;
+ UINTN HelpLine;
+ UINTN HelpHeaderLine;
+ UINTN HelpBottomLine;
+ BOOLEAN MultiHelpPage;
+ UINT16 GlyphWidth;
+ UINT16 EachLineWidth;
+ UINT16 HeaderLineWidth;
+ UINT16 BottomLineWidth;
+ EFI_STRING_ID HelpInfo;
+ UI_EVENT_TYPE EventType;
+ FORM_DISPLAY_ENGINE_STATEMENT *InitialHighlight;
+
+ EventType = UIEventNone;
+ Status = EFI_SUCCESS;
+ HelpString = NULL;
+ HelpHeaderString = NULL;
+ HelpBottomString = NULL;
+ OptionString = NULL;
+ ScreenOperation = UiNoOperation;
+ NewLine = TRUE;
+ DefaultId = 0;
+ HelpPageCount = 0;
+ HelpLine = 0;
+ RowCount = 0;
+ HelpBottomLine = 0;
+ HelpHeaderLine = 0;
+ HelpPageIndex = 0;
+ MultiHelpPage = FALSE;
+ EachLineWidth = 0;
+ HeaderLineWidth = 0;
+ BottomLineWidth = 0;
+ OutputString = NULL;
+ UpArrow = FALSE;
+ DownArrow = FALSE;
+ SkipValue = 0;
+
+ NextMenuOption = NULL;
+ PreviousMenuOption = NULL;
+ SavedMenuOption = NULL;
+ HotKey = NULL;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ ModalSkipColumn = (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;
+ InitialHighlight = gFormData->HighLightedStatement;
+
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
+
+ gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3);
+ gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);
+ gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);
+
+ 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 + ModalSkipColumn;
+ } else {
+ Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;
+ }
+
+ FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue);
+
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ ControlFlag = CfInitialization;
+ while (TRUE) {
+ switch (ControlFlag) {
+ case CfInitialization:
+ if (IsListEmpty (&gMenuOption)) {
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) == 0) {
+ //
+ // Clear Statement range.
+ //
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ gStatementDimensions.RightColumn,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ GetFieldTextColor ()
+ );
+
+ //
+ // Clear Key Range
+ //
+ RefreshKeyHelp (gFormData, NULL, FALSE);
+ }
+
+ ControlFlag = CfReadKey;
+ } else {
+ ControlFlag = CfRepaint;
+ }
+ break;
+
+ case CfRepaint:
+ ControlFlag = CfRefreshHighLight;
+
+ if (Repaint) {
+ //
+ // Display menu
+ //
+ DownArrow = FALSE;
+ UpArrow = FALSE;
+ Row = TopRow;
+
+ Temp = (UINTN) SkipValue;
+ Temp2 = (UINTN) SkipValue;
+ Temp3 = (UINTN) SkipValue;
+
+ //
+ // 1. Clear the screen.
+ //
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ ClearLines (
+ gStatementDimensions.LeftColumn + ModalSkipColumn,
+ gStatementDimensions.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ GetFieldTextColor ()
+ );
+ } else {
+ TempRightCol = gStatementDimensions.RightColumn;
+ if (!mStatementLayoutIsChanged) {
+ TempRightCol = gStatementDimensions.RightColumn - gHelpBlockWidth;
+ }
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ gStatementDimensions.RightColumn,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ TopRow - 1,
+ GetFieldTextColor ()
+ );
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ TempRightCol,
+ TopRow,
+ BottomRow,
+ GetFieldTextColor ()
+ );
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ gStatementDimensions.RightColumn,
+ BottomRow + 1,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ 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 = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn + ModalSkipColumn;
+ } else {
+ MenuOption->OptCol = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn;
+ }
+
+ Statement = MenuOption->ThisTag;
+ if (MenuOption->NestInStatement) {
+ MenuOption->Col += SUBTITLE_INDENT;
+ }
+
+ if (MenuOption->GrayOut) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
+ } else {
+ if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
+ }
+ }
+
+ Width = GetWidth (Statement);
+ OriginalRow = Row;
+ GlyphWidth = 1;
+
+ if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) {
+ //
+ // Print Arrow for Goto button.
+ //
+ PrintCharAt (
+ MenuOption->Col - 2,
+ Row,
+ GEOMETRICSHAPE_RIGHT_TRIANGLE
+ );
+ }
+
+ //
+ // 2.1. Paint the description.
+ //
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ //
+ // Temp means need to skip how many lines from the start.
+ //
+ if ((Temp == 0) && (Row <= BottomRow)) {
+ PrintStringAt (MenuOption->Col, Row, OutputString);
+ }
+ //
+ // 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--;
+ }
+ }
+
+ Temp = 0;
+ Row = OriginalRow;
+
+ //
+ // 2.2. Paint the option string.
+ //
+ Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
+ //
+ // If Error occur, question value update in ProcessOptions.
+ // Exit current FormDisplay with new question value.
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (OptionString != NULL) {
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ ProcessStringForDateTime(MenuOption, OptionString, TRUE);
+ }
+
+ Width = (UINT16) gOptionBlockWidth;
+ OriginalRow = Row;
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp2 == 0) && (Row <= BottomRow)) {
+ PrintStringAt (MenuOption->OptCol, Row, OutputString);
+ }
+ //
+ // 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 - OriginalRow) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp2 != 0) {
+ Temp2--;
+ }
+ }
+
+ Row = OriginalRow;
+
+ FreePool (OptionString);
+ }
+ Temp2 = 0;
+
+ //
+ // 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;
+ OriginalRow = Row;
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp3 == 0) && (Row <= BottomRow)) {
+ PrintStringAt (MenuOption->OptCol, Row, OutputString);
+ }
+ //
+ // 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++;
+ //
+ // 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 - OriginalRow) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp3 != 0) {
+ Temp3--;
+ }
+ }
+
+ Row = OriginalRow;
+ FreePool (StringPtr);
+ }
+ Temp3 = 0;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+
+ //
+ // 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;
+ }
+ }
+
+ if (!ValueIsScroll (TRUE, TopOfScreen)) {
+ UpArrow = TRUE;
+ }
+
+ 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 ());
+ }
+
+ 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;
+
+ if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {
+ Temp = SkipValue;
+ } else {
+ Temp = 0;
+ }
+ if (NewPos == TopOfScreen) {
+ Temp2 = SkipValue;
+ } else {
+ Temp2 = 0;
+ }
+
+ if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {
+ if (MenuOption != NULL) {
+ //
+ // Remove highlight on last Menu Option
+ //
+ gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
+ ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ if (OptionString != NULL) {
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)
+ ) {
+ ProcessStringForDateTime(MenuOption, OptionString, FALSE);
+ }
+
+ Width = (UINT16) gOptionBlockWidth;
+ OriginalRow = MenuOption->Row;
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {
+ PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
+ }
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&OptionString[Index]) != 0) {
+ if (Temp == 0) {
+ MenuOption->Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp != 0) {
+ Temp--;
+ }
+ }
+
+ MenuOption->Row = OriginalRow;
+
+ FreePool (OptionString);
+ } else {
+ if (NewLine) {
+ if (MenuOption->GrayOut) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
+ } else if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
+ }
+
+ OriginalRow = MenuOption->Row;
+ Width = GetWidth (MenuOption->ThisTag);
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {
+ PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
+ }
+ //
+ // 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) {
+ MenuOption->Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp != 0) {
+ Temp--;
+ }
+ }
+
+ MenuOption->Row = OriginalRow;
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+ }
+ }
+
+ //
+ // This is the current selected statement
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ Statement = MenuOption->ThisTag;
+
+ //
+ // Get the highlight statement.
+ //
+ gUserInput->SelectedStatement = Statement;
+ gSequence = (UINT16) MenuOption->Sequence;
+
+ //
+ // Record highlight row info for date/time opcode.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ gHighligthMenuInfo.QuestionId = GetQuestionIdInfo(Statement->OpCode);
+ gHighligthMenuInfo.DisplayRow = (UINT16) MenuOption->Row;
+ } else {
+ gHighligthMenuInfo.QuestionId = 0;
+ gHighligthMenuInfo.DisplayRow = 0;
+ }
+
+ if (!IsSelectable (MenuOption)) {
+ RefreshKeyHelp(gFormData, Statement, FALSE);
+ break;
+ }
+
+ //
+ // Set reverse attribute
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+ gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
+
+ ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
+ if (OptionString != NULL) {
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ ProcessStringForDateTime(MenuOption, OptionString, FALSE);
+ }
+ Width = (UINT16) gOptionBlockWidth;
+
+ OriginalRow = MenuOption->Row;
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {
+ PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
+ }
+ //
+ // 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) {
+ MenuOption->Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp2 != 0) {
+ Temp2--;
+ }
+ }
+
+ MenuOption->Row = OriginalRow;
+
+ FreePool (OptionString);
+ } else {
+ if (NewLine) {
+ OriginalRow = MenuOption->Row;
+
+ Width = GetWidth (Statement);
+ GlyphWidth = 1;
+
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {
+ PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
+ }
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&MenuOption->Description[Index]) != 0) {
+ if (Temp2 == 0) {
+ MenuOption->Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp2 != 0) {
+ Temp2--;
+ }
+ }
+
+ MenuOption->Row = OriginalRow;
+
+ }
+ }
+
+ RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE);
+
+ //
+ // Clear reverse attribute
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+ break;
+
+ case CfUpdateHelpString:
+ ControlFlag = CfPrepareToReadKey;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ break;
+ }
+
+ if (Repaint || NewLine) {
+ //
+ // 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;
+ if (HelpInfo == 0 || !IsSelectable (MenuOption)) {
+ StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ } 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) > 1) {
+ 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 < (UINTN) (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 < (UINTN) (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) {
+ 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.
+ //
+ if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ASSERT(MenuOption != NULL);
+ 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) {
+ //
+ // If the screen has no menu items, and the user didn't select UiReset
+ // ignore the selection and go back to reading keys.
+ //
+ if (IsListEmpty (&gMenuOption)) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+ }
+
+ for (Index = 0;
+ Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
+ 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;
+ }
+
+ //
+ // When user press ESC, it will try to show another menu, should clean the gSequence info.
+ //
+ if (gSequence != 0) {
+ gSequence = 0;
+ }
+
+ gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
+ ControlFlag = CfExit;
+ break;
+
+ case CfUiHotKey:
+ ControlFlag = CfRepaint;
+
+ gUserInput->Action = HotKey->Action;
+ ControlFlag = CfExit;
+ 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;
+
+ SavedListEntry = NewPos;
+
+ ASSERT(NewPos != NULL);
+ //
+ // Adjust Date/Time position before we advance forward.
+ //
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+ if (NewPos->BackLink != &gMenuOption) {
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ ASSERT (MenuOption != NULL);
+ NewLine = TRUE;
+ NewPos = NewPos->BackLink;
+
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ if (PreviousMenuOption->Row == 0) {
+ UpdateOptionSkipLines (PreviousMenuOption);
+ }
+ DistanceValue = PreviousMenuOption->Skip;
+ Difference = 0;
+ if (MenuOption->Row >= DistanceValue + TopRow) {
+ Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);
+ }
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (Difference < 0) {
+ //
+ // We hit the begining MenuOption that can be focused
+ // so we simply scroll to the top.
+ //
+ if (TopOfScreen != gMenuOption.ForwardLink) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ Repaint = TRUE;
+ } else {
+ //
+ // Scroll up to the last page when we have arrived at top page.
+ //
+ NewPos = &gMenuOption;
+ TopOfScreen = &gMenuOption;
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ ScreenOperation = UiPageUp;
+ ControlFlag = CfScreenOperation;
+ break;
+ }
+ } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {
+ //
+ // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
+ //
+ TopOfScreen = NewPos;
+ Repaint = TRUE;
+ SkipValue = 0;
+ } else if (!IsSelectable (NextMenuOption)) {
+ //
+ // Continue to go up until scroll to next page or the selectable option is found.
+ //
+ ScreenOperation = UiUp;
+ ControlFlag = CfScreenOperation;
+ }
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+ } else {
+ //
+ // Scroll up to the last page.
+ //
+ NewPos = &gMenuOption;
+ TopOfScreen = &gMenuOption;
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ ScreenOperation = UiPageUp;
+ ControlFlag = CfScreenOperation;
+ }
+ break;
+
+ case CfUiPageUp:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+
+ ASSERT(NewPos != NULL);
+ //
+ // Already at the first menu option, Check the skip value.
+ //
+ if (NewPos->BackLink == &gMenuOption) {
+ if (SkipValue == 0) {
+ NewLine = FALSE;
+ Repaint = FALSE;
+ } else {
+ NewLine = TRUE;
+ Repaint = TRUE;
+ SkipValue = 0;
+ }
+ break;
+ }
+
+ NewLine = TRUE;
+ Repaint = TRUE;
+
+ //
+ // 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.
+ //
+ if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {
+ SkipValue -= BottomRow - TopRow + 1;
+ break;
+ }
+
+ Link = TopOfScreen;
+ //
+ // First minus the menu of the top screen, it's value is SkipValue.
+ //
+ Index = (BottomRow + 1) - SkipValue;
+ while ((Index > TopRow) && (Link->BackLink != &gMenuOption)) {
+ Link = Link->BackLink;
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
+ if (PreviousMenuOption->Row == 0) {
+ UpdateOptionSkipLines (PreviousMenuOption);
+ }
+ if (Index < PreviousMenuOption->Skip) {
+ break;
+ }
+ Index = Index - PreviousMenuOption->Skip;
+ }
+
+ if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {
+ SkipValue = 0;
+ if (TopOfScreen == &gMenuOption) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ NewPos = gMenuOption.BackLink;
+ MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);
+ Repaint = FALSE;
+ } else if (TopOfScreen != Link) {
+ TopOfScreen = Link;
+ NewPos = Link;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
+ } else {
+ //
+ // Finally we know that NewPos is the last MenuOption can be focused.
+ //
+ Repaint = FALSE;
+ NewPos = Link;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
+ }
+ } else {
+ if (Index > TopRow) {
+ //
+ // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
+ //
+ SkipValue = PreviousMenuOption->Skip - (Index - TopRow);
+ } else if (Index == TopRow) {
+ SkipValue = 0;
+ } else {
+ SkipValue = TopRow - Index;
+ }
+
+ //
+ // Move to the option in Next page.
+ //
+ if (TopOfScreen == &gMenuOption) {
+ NewPos = gMenuOption.BackLink;
+ MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);
+ } else {
+ NewPos = Link;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
+ }
+
+ //
+ // There are more MenuOption needing scrolling up.
+ //
+ TopOfScreen = Link;
+ MenuOption = NULL;
+ }
+
+ //
+ // 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);
+ break;
+
+ case CfUiPageDown:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+
+ ASSERT (NewPos != NULL);
+ if (NewPos->ForwardLink == &gMenuOption) {
+ NewLine = FALSE;
+ Repaint = FALSE;
+ break;
+ }
+
+ 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)) {
+ //
+ // Finally we know that NewPos is the last MenuOption can be focused.
+ //
+ Repaint = FALSE;
+ MoveToNextStatement (TRUE, &Link, Index - TopRow);
+ } 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);
+ }
+
+ //
+ // Save the menu as the next highlight menu.
+ //
+ NewPos = Link;
+
+ //
+ // 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);
+ 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;
+
+ //
+ // 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.
+ //
+ SavedListEntry = NewPos;
+ AdjustDateAndTimePosition (FALSE, &NewPos);
+
+ if (NewPos->ForwardLink != &gMenuOption) {
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ NewLine = TRUE;
+ NewPos = NewPos->ForwardLink;
+
+ Difference = 0;
+ //
+ // Current menu not at the bottom of the form.
+ //
+ if (BottomRow >= MenuOption->Row + MenuOption->Skip) {
+ //
+ // Find the next selectable menu.
+ //
+ Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);
+ //
+ // We hit the end of MenuOption that can be focused
+ // so we simply scroll to the first page.
+ //
+ if (Difference < 0) {
+ //
+ // Scroll to the first page.
+ //
+ if (TopOfScreen != gMenuOption.ForwardLink) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ } else {
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ }
+ NewPos = gMenuOption.ForwardLink;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
+
+ 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);
+ break;
+ }
+ }
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ if (NextMenuOption->Row == 0) {
+ UpdateOptionSkipLines (NextMenuOption);
+ }
+ DistanceValue = Difference + NextMenuOption->Skip;
+
+ Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;
+ if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&
+ (NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP ||
+ NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)
+ ) {
+ Temp ++;
+ }
+
+ //
+ // If we are going to scroll, update TopOfScreen
+ //
+ if (Temp > BottomRow) {
+ do {
+ //
+ // Is the current top of screen a zero-advance op-code?
+ // If so, keep moving forward till we hit a >0 advance op-code
+ //
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+
+ //
+ // If bottom op-code is more than one line or top op-code is more than one line
+ //
+ if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) {
+ //
+ // Is the bottom op-code greater than or equal in size to the top op-code?
+ //
+ if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {
+ //
+ // Skip the top op-code
+ //
+ TopOfScreen = TopOfScreen->ForwardLink;
+ Difference = (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
+ //
+ while (Difference >= (INTN) SavedMenuOption->Skip) {
+ //
+ // Since the Difference is greater than or equal to this op-code's skip value, skip it
+ //
+ Difference = Difference - (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.
+ //
+ SkipValue = Difference - 1;
+ } 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) - 1;
+ }
+ } else {
+ if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {
+ TopOfScreen = TopOfScreen->ForwardLink;
+ break;
+ }
+ }
+ //
+ // If the op-code at the top of the screen is more than one line, let's not skip it yet
+ // Let's set a skip flag to smoothly scroll the top of the screen.
+ //
+ if (SavedMenuOption->Skip > 1) {
+ if (SavedMenuOption == NextMenuOption) {
+ SkipValue = 0;
+ } else {
+ SkipValue++;
+ }
+ } else if (SavedMenuOption->Skip == 1) {
+ SkipValue = 0;
+ } else {
+ SkipValue = 0;
+ TopOfScreen = TopOfScreen->ForwardLink;
+ }
+ } while (SavedMenuOption->Skip == 0);
+
+ 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;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ } else {
+ //
+ // Scroll to the first page.
+ //
+ if (TopOfScreen != gMenuOption.ForwardLink) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ } else {
+ //
+ // Need to remove the current highlight menu.
+ // MenuOption saved the last highlight menu info.
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ }
+
+ SkipValue = 0;
+ NewLine = TRUE;
+ //
+ // Get the next highlight menu.
+ //
+ NewPos = gMenuOption.ForwardLink;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
+ }
+
+ //
+ // 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);
+ break;
+
+ case CfUiNoOperation:
+ ControlFlag = CfRepaint;
+ break;
+
+ case CfExit:
+ if (HelpString != NULL) {
+ FreePool (HelpString);
+ }
+ if (HelpHeaderString != NULL) {
+ FreePool (HelpHeaderString);
+ }
+ if (HelpBottomString != NULL) {
+ FreePool (HelpBottomString);
+ }
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+
+ Base on the browser status info to show an pop up message.
+
+**/
+VOID
+BrowserStatusProcess (
+ VOID
+ )
+{
+ CHAR16 *ErrorInfo;
+ EFI_INPUT_KEY Key;
+
+ if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
+ return;
+ }
+
+ if (gFormData->ErrorString != NULL) {
+ ErrorInfo = gFormData->ErrorString;
+ } else {
+ switch (gFormData->BrowserStatus) {
+ case BROWSER_SUBMIT_FAIL:
+ ErrorInfo = gSaveFailed;
+ break;
+
+ case BROWSER_NO_SUBMIT_IF:
+ ErrorInfo = gNoSubmitIf;
+ break;
+
+ case BROWSER_FORM_NOT_FOUND:
+ ErrorInfo = gFormNotFound;
+ break;
+
+ case BROWSER_FORM_SUPPRESS:
+ ErrorInfo = gFormSuppress;
+ break;
+
+ case BROWSER_PROTOCOL_NOT_FOUND:
+ ErrorInfo = gProtocolNotFound;
+ break;
+
+ default:
+ ErrorInfo = gBrwoserError;
+ break;
+ }
+ }
+
+ //
+ // Error occur, prompt error message.
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+}
+
+/**
+ 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 (UserInputData == NULL) {
+ //
+ // UserInputData == NULL, means only need to print the error info, return here.
+ //
+ return EFI_SUCCESS;
+ }
+
+ ConvertStatementToMenu();
+
+ Status = DisplayPageFrame (FormData, &gStatementDimensions);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem (&gOldStatementDimensions, &gStatementDimensions, sizeof (gStatementDimensions)) == 0) {
+ mStatementLayoutIsChanged = FALSE;
+ } else {
+ mStatementLayoutIsChanged = TRUE;
+ CopyMem (&gOldStatementDimensions, &gStatementDimensions, sizeof (gStatementDimensions));
+ }
+
+ Status = UiDisplayMenu(FormData);
+
+ return Status;
+}
+
+/**
+ 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);
+
+ InitializeDisplayStrings();
+
+ //
+ // 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);
+
+ 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);
+ }
+
+ 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 ();
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h new file mode 100644 index 0000000000..ad4684efc3 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h @@ -0,0 +1,580 @@ +/** @file
+ FormDiplay protocol to show Form
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 <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;
+
+//
+// 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 gPromptBlockWidth;
+extern CHAR16 gOptionBlockWidth;
+extern CHAR16 gHelpBlockWidth;
+extern CHAR16 *mUnknownString;
+
+//
+// Screen definitions
+//
+
+#define LEFT_SKIPPED_COLUMNS 3
+#define SCROLL_ARROW_HEIGHT 1
+#define POPUP_PAD_SPACE_COUNT 5
+#define POPUP_FRAME_WIDTH 2
+
+//
+// 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]
+//
+#define MAX_NUMERIC_INPUT_WIDTH 23
+
+#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;
+} 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,
+ CfUiDefault,
+ 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_QUESTION_ID QuestionId;
+ UINT16 DisplayRow;
+} DISPLAY_HIGHLIGHT_MENU_INFO;
+
+#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)
+
+/**
+ 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
+ );
+
+/**
+ Exit Display and Clear Screen to the original state.
+
+**/
+VOID
+EFIAPI
+ExitDisplay (
+ VOID
+ );
+
+/**
+ Process validate for one question.
+
+ @param Question The question which need to validate.
+
+ @retval EFI_SUCCESS Question Option process success.
+ @retval Other Question Option process fail.
+
+**/
+EFI_STATUS
+ValidateQuestion (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni Binary files differnew file mode 100644 index 0000000000..0ee7f46302 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c b/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c new file mode 100644 index 0000000000..607f0df83c --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c @@ -0,0 +1,1531 @@ +/** @file
+Implementation for handling user input from the User Interfaces.
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+ 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;
+ }
+
+ TempString = AllocateZeroPool ((Maximum + 1)* 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;
+
+ 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;
+ }
+
+ break;
+
+ 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
+ //
+ StrCpy (StringPtr, 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)) {
+ StrnCpy (StringPtr, &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;
+ StrCat (TempString, KeyPad);
+ StrCat (TempString, StringPtr + CurrentCursor);
+ StrCpy (StringPtr, TempString);
+ } else {
+ StrCat (StringPtr, 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 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,
+ 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:
+ *Minimum = NumericOp->data.u8.MinValue;
+ *Maximum = NumericOp->data.u8.MaxValue;
+ *Step = NumericOp->data.u8.Step;
+ *StorageWidth = (UINT16) sizeof (UINT8);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ *Minimum = NumericOp->data.u16.MinValue;
+ *Maximum = NumericOp->data.u16.MaxValue;
+ *Step = NumericOp->data.u16.Step;
+ *StorageWidth = (UINT16) sizeof (UINT16);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ *Minimum = NumericOp->data.u32.MinValue;
+ *Maximum = NumericOp->data.u32.MaxValue;
+ *Step = NumericOp->data.u32.Step;
+ *StorageWidth = (UINT16) sizeof (UINT32);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ *Minimum = NumericOp->data.u64.MinValue;
+ *Maximum = NumericOp->data.u64.MaxValue;
+ *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
+ )
+{
+ EFI_STATUS Status;
+ 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 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;
+
+ Question = MenuOption->ThisTag;
+ QuestionValue = &Question->CurrentValue;
+
+ //
+ // 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, &Minimum, &Maximum, &Step, &StorageWidth);
+ EditValue = QuestionValue->Value.u64;
+ EraseLen = gOptionBlockWidth;
+ }
+
+ if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL) &&
+ ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
+ HexInput = TRUE;
+ } else {
+ HexInput = FALSE;
+ }
+
+ //
+ // 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;
+ }
+ }
+
+ 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' ');
+ } else {
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ }
+
+ if (MenuOption->Sequence == 2) {
+ InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
+ } else {
+ InputText[InputWidth + 1] = DATE_SEPARATOR;
+ }
+ InputText[InputWidth + 2] = 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' ');
+ } else {
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ }
+
+ if (MenuOption->Sequence == 2) {
+ InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
+ } else {
+ InputText[InputWidth + 1] = TIME_SEPARATOR;
+ }
+ InputText[InputWidth + 2] = 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;
+ }
+
+ Status = WaitForKeyStroke (&Key);
+
+TheKey2:
+ switch (Key.UnicodeChar) {
+
+ case '+':
+ case '-':
+ if (Key.UnicodeChar == '+') {
+ Key.ScanCode = SCAN_RIGHT;
+ } else {
+ Key.ScanCode = SCAN_LEFT;
+ }
+ Key.UnicodeChar = CHAR_NULL;
+ goto TheKey2;
+
+ 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 (EditValue >= Minimum + Step) {
+ EditValue = EditValue - Step;
+ } else if (EditValue > Minimum){
+ EditValue = Minimum;
+ } else {
+ EditValue = Maximum;
+ }
+ } else if (Key.ScanCode == SCAN_RIGHT) {
+ 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;
+ break;
+
+ 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.
+ //
+ if (EditValue < Minimum) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ break;
+ } else {
+ 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 ValidateQuestion (Question);
+ break;
+
+ case CHAR_BACKSPACE:
+ if (ManualInput) {
+ if (Count == 0) {
+ 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 {
+ EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
+ }
+ } else {
+ if (HexInput) {
+ EditValue = Digital;
+ } else {
+ EditValue = Key.UnicodeChar - L'0';
+ }
+ }
+
+ if (EditValue > Maximum) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));
+ EditValue = PreviousNumber[Count];
+ break;
+ } else {
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+ }
+
+ Count++;
+ ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));
+ 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 Value1->u8 == Value2->u8;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ return Value1->u16 == Value2->u16;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ return Value1->u32 == Value2->u32;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ return 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_STATUS Status;
+ 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;
+
+ StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
+ ASSERT (StringPtr);
+
+ 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;
+ StrCat (StringPtr, 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;
+ }
+
+ Status = 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;
+ Status = EFI_SUCCESS;
+ }
+ } 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);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
+
+ return ValidateQuestion (Question);
+
+ default:
+ break;
+ }
+ } while (TRUE);
+
+}
+
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/Print.c b/MdeModulePkg/Universal/DisplayEngineDxe/Print.c new file mode 100644 index 0000000000..f5a95c4ab1 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/Print.c @@ -0,0 +1,54 @@ +/** @file
+Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very
+simple implemenation of SPrint() and Print() to support debug.
+
+You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a
+time. This makes the implementation very simple.
+
+VSPrint, Print, SPrint format specification has the follwoing form
+
+%type
+
+type:
+ 'S','s' - argument is an Unicode string
+ 'c' - argument is an ascii character
+ '%' - Print a %
+
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FormDisplay.h"
+
+
+/**
+ 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;
+ }
+}
+
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c new file mode 100644 index 0000000000..aca043a8c2 --- /dev/null +++ b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c @@ -0,0 +1,1286 @@ +/** @file
+Implementation for handling the User Interface option processing.
+
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FormDisplay.h"
+
+/**
+ Concatenate a narrow string to another string.
+
+ @param Destination The destination string.
+ @param Source The source string. The string to be concatenated.
+ to the end of Destination.
+
+**/
+VOID
+NewStrCat (
+ IN OUT CHAR16 *Destination,
+ 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++;
+
+ StrCpy (Destination + Length, Source);
+}
+
+/**
+ 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;
+
+ if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {
+ if (Value1->Type != EFI_IFR_TYPE_BUFFER && Value2->Type != EFI_IFR_TYPE_BUFFER) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
+ if (Value1->Type != Value2->Type) {
+ //
+ // Both Operator should be type of String
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ 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;
+ }
+
+ if (Value1->Type == EFI_IFR_TYPE_BUFFER || Value2->Type == EFI_IFR_TYPE_BUFFER ) {
+ if (Value1->Type != Value2->Type) {
+ //
+ // Both Operator should be type of Buffer.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ Len = Value1->BufferLen > Value2->BufferLen ? Value2->BufferLen : Value1->BufferLen;
+ *Result = CompareMem (Value1->Buffer, Value2->Buffer, Len);
+ if ((*Result == 0) && (Value1->BufferLen != Value2->BufferLen))
+ {
+ //
+ // In this case, means base on samll number buffer, the data is same
+ // So which value has more data, which value is bigger.
+ //
+ *Result = Value1->BufferLen > Value2->BufferLen ? 1 : -1;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Take remain types(integer, boolean, date/time) as integer
+ //
+ Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
+ if (Temp64 > 0) {
+ *Result = 1;
+ } else if (Temp64 < 0) {
+ *Result = -1;
+ } else {
+ *Result = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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;
+ break;
+ }
+
+ 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 validate for one question.
+
+ @param Question The question need to be validate.
+
+ @retval EFI_SUCCESS Question Option process success.
+ @retval EFI_INVALID_PARAMETER Question Option process fail.
+
+**/
+EFI_STATUS
+ValidateQuestion (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question
+ )
+{
+ CHAR16 *ErrorInfo;
+ EFI_INPUT_KEY Key;
+ EFI_STATUS Status;
+ STATEMENT_ERROR_INFO RetInfo;
+ UINT32 RetVal;
+
+ if (Question->ValidateQuestion == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ RetVal = Question->ValidateQuestion(gFormData, Question, &gUserInput->InputValue, &RetInfo);
+
+ switch (RetVal) {
+ case INCOSISTENT_IF_TRUE:
+ //
+ // Condition meet, show up error message
+ //
+ ASSERT (RetInfo.StringId != 0);
+ ErrorInfo = GetToken (RetInfo.StringId, gFormData->HiiHandle);
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ FreePool (ErrorInfo);
+
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ 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.
+ //
+ 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)) {
+ 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;
+ }
+
+ 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);
+ 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);
+ 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);
+ FreePool (StringPtr);
+
+ Status = ValidateQuestion (Question);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset state machine for password
+ //
+ Question->PasswordCheck (gFormData, Question, NULL);
+ }
+
+ return Status;
+ } 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;
+ }
+
+ FreePool (TempString);
+ FreePool (StringPtr);
+
+ return Status;
+}
+
+/**
+ 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_STRING_ID StringId;
+ EFI_IFR_ORDERED_LIST *OrderList;
+ BOOLEAN ValueInvalid;
+
+ Status = EFI_SUCCESS;
+
+ StringPtr = NULL;
+ Character[1] = L'\0';
+ *OptionString = NULL;
+ StringId = 0;
+ 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.
+ //
+ *OptionString = AllocateZeroPool (OrderList->MaxContainers * BufferSize);
+ 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) {
+ 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;
+
+ 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], Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], Character);
+ Character[0] = CHAR_CARRIAGE_RETURN;
+ NewStrCat (OptionString[0], 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;
+ }
+
+ if (SkipErrorValue) {
+ //
+ // Not report error, just get the correct option string info.
+ //
+ Character[0] = LEFT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], Character);
+ Character[0] = CHAR_CARRIAGE_RETURN;
+ NewStrCat (OptionString[0], 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;
+
+ 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 {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ OneOfOption = ValueToOption (Question, QuestionValue);
+ if (OneOfOption == NULL) {
+ 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);
+
+ CopyMem (&gUserInput->InputValue.Value, &Option->OptionOpCode->Value, sizeof (EFI_IFR_TYPE_VALUE));
+ gUserInput->InputValue.Type = Option->OptionOpCode->Type;
+ gUserInput->SelectedStatement = Question;
+
+ FreePool (*OptionString);
+ *OptionString = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Character[0] = LEFT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], 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 ValidateQuestion (Question);
+ } 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;
+ 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' ');
+ 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' ');
+ 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;
+ 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' ');
+ 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' ');
+ 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 ValidateQuestion (Question);
+ } 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;
+}
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index cd29e29438..44dae1ba03 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -787,7 +787,7 @@ FORM_BROWSER_FORM * IdToForm (
IN FORM_BROWSER_FORMSET *FormSet,
IN UINT16 FormId
-)
+ )
{
LIST_ENTRY *Link;
FORM_BROWSER_FORM *Form;
@@ -2105,7 +2105,7 @@ GetQuestionValueFromForm ( //
FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
ASSERT (FormSet != NULL);
- Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet, FALSE);
+ Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);
if (EFI_ERROR (Status)) {
GetTheVal = FALSE;
goto Done;
@@ -2800,7 +2800,7 @@ EvaluateExpression ( for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);
}
- Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer);
+ Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
FreePool (NameValue);
if (!EFI_ERROR (Status)) {
Data1.Value.b = TRUE;
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h new file mode 100644 index 0000000000..5660a997b8 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h @@ -0,0 +1,265 @@ +/** @file
+Private structure, MACRO and function definitions for User Interface related functionalities.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EXPRESSION_H_
+#define _EXPRESSION_H_
+
+/**
+ Get the expression list count.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval >=0 The expression count
+ @retval -1 Input parameter error.
+
+**/
+INTN
+GetConditionalExpressionCount (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ );
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ );
+
+/**
+ Get the expression Buffer pointer.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval The start pointer of the expression buffer or NULL.
+
+**/
+FORM_EXPRESSION **
+GetConditionalExpressionList (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ );
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ );
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ );
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ );
+
+/**
+ Push the expression options onto the Stack.
+
+ @param Pointer Pointer to the current expression.
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushConditionalExpression (
+ IN FORM_EXPRESSION *Pointer,
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop the expression options from the Stack
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopConditionalExpression (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ );
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ );
+
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression
+ );
+/**
+ Return the result of the expression list. Check the expression list and
+ return the highest priority express result.
+ Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
+
+ @param ExpList The input expression list.
+ @param Evaluate Whether need to evaluate the expression first.
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+
+ @retval EXPRESS_RESULT Return the higher priority express result.
+ DisableIf > SuppressIf > GrayOutIf > FALSE
+
+**/
+EXPRESS_RESULT
+EvaluateExpressionList (
+ IN FORM_EXPRESSION_LIST *ExpList,
+ IN BOOLEAN Evaluate,
+ IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
+ IN FORM_BROWSER_FORM *Form OPTIONAL
+ );
+
+/**
+ Get Form given its FormId.
+
+ @param FormSet The formset which contains this form.
+ @param FormId Id of this form.
+
+ @retval Pointer The form.
+ @retval NULL Specified Form is not found in the formset.
+
+**/
+FORM_BROWSER_FORM *
+IdToForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT16 FormId
+ );
+
+#endif // _EXPRESSION_H
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index 2464aebd09..1c3ab2bedc 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. UINT16 mStatementIndex;
UINT16 mExpressionOpCodeIndex;
-
+EFI_QUESTION_ID mUsedQuestionId;
BOOLEAN mInScopeSubtitle;
extern LIST_ENTRY gBrowserStorageList;
/**
@@ -42,9 +42,9 @@ CreateStatement ( if (Form == NULL) {
//
- // We are currently not in a Form Scope, so just skip this Statement
+ // Only guid op may out side the form level.
//
- return NULL;
+ ASSERT (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP);
}
Statement = &FormSet->StatementBuffer[mStatementIndex];
@@ -58,6 +58,7 @@ CreateStatement ( Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;
Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Statement->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData;
StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
@@ -82,8 +83,11 @@ CreateStatement ( //
// Insert this Statement into current Form
//
- InsertTailList (&Form->StatementListHead, &Statement->Link);
-
+ if (Form == NULL) {
+ InsertTailList (&FormSet->StatementListOSF, &Statement->Link);
+ } else {
+ InsertTailList (&Form->StatementListHead, &Statement->Link);
+ }
return Statement;
}
@@ -1133,6 +1137,7 @@ ParseOpCodes ( CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
mStatementIndex = 0;
+ mUsedQuestionId = 1;
FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
if (FormSet->StatementBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
@@ -1144,6 +1149,7 @@ ParseOpCodes ( return EFI_OUT_OF_RESOURCES;
}
+ InitializeListHead (&FormSet->StatementListOSF);
InitializeListHead (&FormSet->StorageListHead);
InitializeListHead (&FormSet->DefaultStoreListHead);
InitializeListHead (&FormSet->FormListHead);
@@ -1502,7 +1508,6 @@ ParseOpCodes ( InitializeListHead (&CurrentForm->ConfigRequestHead);
CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
- CurrentForm->NvUpdateRequired = FALSE;
CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16));
CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
@@ -1539,7 +1544,6 @@ ParseOpCodes ( CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
ASSERT (CurrentForm != NULL);
CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
- CurrentForm->NvUpdateRequired = FALSE;
InitializeListHead (&CurrentForm->ExpressionListHead);
InitializeListHead (&CurrentForm->StatementListHead);
InitializeListHead (&CurrentForm->ConfigRequestHead);
@@ -1653,7 +1657,7 @@ ParseOpCodes ( ASSERT (CurrentStatement != NULL);
CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;
-
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
if (Scope != 0) {
mInScopeSubtitle = TRUE;
}
@@ -1662,13 +1666,14 @@ ParseOpCodes ( case EFI_IFR_TEXT_OP:
CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
ASSERT (CurrentStatement != NULL);
-
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
break;
case EFI_IFR_RESET_BUTTON_OP:
CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
ASSERT (CurrentStatement != NULL);
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
break;
@@ -1913,6 +1918,7 @@ ParseOpCodes ( CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
ASSERT (CurrentOption != NULL);
CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
+ CurrentOption->OpCode = (EFI_IFR_ONE_OF_OPTION *) OpCodeData;
CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
@@ -2270,45 +2276,8 @@ ParseOpCodes ( //
// Vendor specific
//
- case EFI_IFR_GUID_OP:
- if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
- //
- // Tiano specific GUIDed opcodes
- //
- switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {
- case EFI_IFR_EXTEND_OP_LABEL:
- //
- // just ignore label
- //
- break;
-
- case EFI_IFR_EXTEND_OP_BANNER:
- //
- // By SubClass to get Banner Data from Front Page
- //
- if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
- CopyMem (
- &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][
- ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],
- &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,
- sizeof (EFI_STRING_ID)
- );
- }
- break;
-
- case EFI_IFR_EXTEND_OP_CLASS:
- CopyMem (&FormSet->Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16));
- break;
-
- case EFI_IFR_EXTEND_OP_SUBCLASS:
- CopyMem (&FormSet->SubClass, &((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass, sizeof (UINT16));
- break;
-
- default:
- break;
- }
- }
-
+ case EFI_IFR_GUID_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
break;
//
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index 4cd71e5d44..def18fd9f9 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -19,863 +19,1658 @@ UI_MENU_SELECTION *gCurrentSelection; EFI_HII_HANDLE mCurrentHiiHandle = NULL;
EFI_GUID mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINT16 mCurrentFormId = 0;
+EFI_EVENT mValueChangedEvent = NULL;
+LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
+UINT32 gBrowserStatus = BROWSER_SUCCESS;
+CHAR16 *gErrorInfo;
+UINT16 mCurFakeQestId;
+FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
/**
- Clear retangle with specified text attribute.
+ Evaluate all expressions in a Form.
+
+ @param FormSet FormSet this Form belongs to.
+ @param Form The Form.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+
+**/
+EFI_STATUS
+EvaluateFormExpressions (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ while (!IsNull (&Form->ExpressionListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ExpressionListHead, Link);
+
+ if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||
+ Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||
+ Expression->Type == EFI_HII_EXPRESSION_WRITE ||
+ (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {
+ //
+ // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
+ //
+ continue;
+ }
+
+ Status = EvaluateExpression (FormSet, Form, Expression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add empty function for event process function.
- @param LeftColumn Left column of retangle.
- @param RightColumn Right column of retangle.
- @param TopRow Start row of retangle.
- @param BottomRow End row of retangle.
- @param TextAttribute The character foreground and background.
+ @param Event The Event need to be process
+ @param Context The context of the event.
**/
VOID
-ClearLines (
- IN UINTN LeftColumn,
- IN UINTN RightColumn,
- IN UINTN TopRow,
- IN UINTN BottomRow,
- IN UINTN TextAttribute
+EFIAPI
+SetupBrowserEmptyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
)
{
- CHAR16 *Buffer;
- UINTN Row;
+}
- //
- // For now, allocate an arbitrarily long buffer
- //
- Buffer = AllocateZeroPool (0x10000);
- ASSERT (Buffer != NULL);
+/**
+ Base on the opcode buffer info to get the display statement.
- //
- // Set foreground and background as defined
- //
- gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);
+ @param OpCode The input opcode buffer for this statement.
+
+ @retval Statement The statement use this opcode buffer.
+
+**/
+FORM_DISPLAY_ENGINE_STATEMENT *
+GetDisplayStatement (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gDisplayFormData.StatementListHead);
+ while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {
+ DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+
+ if (DisplayStatement->OpCode == OpCode) {
+ return DisplayStatement;
+ }
+ Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Free the refresh event list.
+
+**/
+VOID
+FreeRefreshEvent (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+
+ while (!IsListEmpty (&mRefreshEventList)) {
+ Link = GetFirstNode (&mRefreshEventList);
+ EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);
+ RemoveEntryList (&EventNode->Link);
+
+ gBS->CloseEvent (EventNode->RefreshEvent);
+
+ FreePool (EventNode);
+ }
+}
+
+/**
+ Check whether this statement value is changed. If yes, update the statement value and return TRUE;
+ else return FALSE.
+
+ @param Statement The statement need to check.
+
+**/
+VOID
+UpdateStatement (
+ IN OUT FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
//
- // Much faster to buffer the long string instead of print it a character at a time
+ // Reset FormPackage update flag
//
- SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');
+ mHiiPackageListUpdated = FALSE;
//
- // Clear the desired area with the appropriate foreground/background
+ // Question value may be changed, need invoke its Callback()
//
- for (Row = TopRow; Row <= BottomRow; Row++) {
- PrintStringAt (LeftColumn, Row, Buffer);
+ ProcessCallBackFunction (gCurrentSelection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
+
+ if (mHiiPackageListUpdated) {
+ //
+ // Package list is updated, force to reparse IFR binary of target Formset
+ //
+ mHiiPackageListUpdated = FALSE;
+ gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
}
+}
- gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);
+/**
+ Refresh the question which has refresh guid event attribute.
+
+ @param Event The event which has this function related.
+ @param Context The input context info related to this event or the status code return to the caller.
+**/
+VOID
+EFIAPI
+RefreshEventNotify(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
- FreePool (Buffer);
- return ;
+ Statement = (FORM_BROWSER_STATEMENT *)Context;
+ UpdateStatement(Statement);
+ gBS->SignalEvent (mValueChangedEvent);
}
+
/**
- Concatenate a narrow string to another string.
+ Create refresh hook event for statement which has refresh event or interval.
- @param Destination The destination string.
- @param Source The source string. The string to be concatenated.
- to the end of Destination.
+ @param Statement The statement need to check.
**/
VOID
-NewStrCat (
- IN OUT CHAR16 *Destination,
- IN CHAR16 *Source
+CreateRefreshEvent (
+ IN FORM_BROWSER_STATEMENT *Statement
)
{
- UINTN Length;
-
- for (Length = 0; Destination[Length] != 0; Length++)
- ;
+ EFI_STATUS Status;
+ EFI_EVENT RefreshEvent;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
//
- // 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
+ // If question has refresh guid, create the notify function.
//
- Destination[Length] = NARROW_CHAR;
- Length++;
-
- StrCpy (Destination + Length, Source);
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ RefreshEventNotify,
+ Statement,
+ &Statement->RefreshGuid,
+ &RefreshEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
+ ASSERT (EventNode != NULL);
+ EventNode->RefreshEvent = RefreshEvent;
+ InsertTailList(&mRefreshEventList, &EventNode->Link);
}
/**
- Count the storage space of a Unicode string.
+ Perform value check for a question.
+
+ @param Question The question need to do check.
+ @param ErrorInfo Return info about the error.
+
+ @retval The check result.
+**/
+UINT32
+InConsistentIfCheck (
+ IN FORM_BROWSER_STATEMENT *Question,
+ OUT STATEMENT_ERROR_INFO *ErrorInfo
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+ LIST_ENTRY *ListHead;
+ UINT32 RetVal;
- 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.
+ RetVal = STATEMENT_VALID;
+ ListHead = &Question->InconsistentListHead;
- If String is NULL, then ASSERT ().
+ Link = GetFirstNode (ListHead);
+ while (!IsNull (ListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ Link = GetNextNode (ListHead, Link);
- @param String The input string to be counted.
+ //
+ // Evaluate the expression
+ //
+ Status = EvaluateExpression (gCurrentSelection->FormSet, gCurrentSelection->Form, Expression);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {
+ ErrorInfo->StringId = Expression->Error;
+ ErrorInfo->TimeOut = 0;
+ RetVal = INCOSISTENT_IF_TRUE;
+ break;
+ }
+ }
- @return Storage space for the input string.
+ return RetVal;
+}
+/**
+ Perform value check for a question.
+
+ @param Form Form where Statement is in.
+ @param Statement Value will check for it.
+ @param InputValue New value will be checked.
+ @param ErrorInfo Return the error info for this check.
+
+ @retval TRUE Input Value is valid.
+ @retval FALSE Input Value is invalid.
**/
-UINTN
-GetStringWidth (
- IN CHAR16 *String
+UINT32
+EFIAPI
+QuestionCheck (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_HII_VALUE *InputValue,
+ OUT STATEMENT_ERROR_INFO *ErrorInfo
)
{
- UINTN Index;
- UINTN Count;
- UINTN IncrementValue;
+ FORM_BROWSER_STATEMENT *Question;
+ EFI_HII_VALUE BackUpValue;
+ UINT8 *BackUpBuffer;
+ UINT32 RetVal;
+
+ BackUpBuffer = NULL;
+ RetVal = STATEMENT_VALID;
+
+ ASSERT (Form != NULL && Statement != NULL && InputValue != NULL && ErrorInfo != NULL);
+
+ Question = GetBrowserStatement(Statement);
+ ASSERT (Question != NULL);
+
+ //
+ // Back up the quesion value.
+ //
+ switch (Question->Operand) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ BackUpBuffer = AllocateCopyPool (Question->StorageWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ CopyMem (Question->BufferValue, InputValue->Buffer, Question->StorageWidth);
+ break;
- ASSERT (String != NULL);
- if (String == NULL) {
- return 0;
+ default:
+ CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
+ CopyMem (&Question->HiiValue, InputValue, sizeof (EFI_HII_VALUE));
+ break;
}
- Index = 0;
- Count = 0;
- IncrementValue = 1;
+ //
+ // Do the inconsistentif check.
+ //
+ if (!IsListEmpty (&Question->InconsistentListHead)) {
+ RetVal = InConsistentIfCheck(Question, ErrorInfo);
+ }
- 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
- )
- ;
+ //
+ // Restore the quesion value.
+ //
+ switch (Question->Operand) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ CopyMem (Question->BufferValue, BackUpBuffer, Question->StorageWidth);
+ break;
- //
- // We hit the null-terminator, we now have a count
- //
- if (String[Index] == 0) {
- break;
+ default:
+ CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
+ break;
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Initialize the Display statement structure data.
+
+ @param DisplayStatement Pointer to the display Statement data strucure.
+ @param Statement The statement need to check.
+ @param HostDisplayStatement Pointer to the display Statement data strucure which is an host statement.
+**/
+VOID
+InitializeDisplayStatement (
+ IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
+ IN FORM_BROWSER_STATEMENT *Statement,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ DISPLAY_QUESTION_OPTION *DisplayOption;
+
+ DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
+ DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
+ DisplayStatement->OpCode = Statement->OpCode;
+ InitializeListHead (&DisplayStatement->NestStatementList);
+ InitializeListHead (&DisplayStatement->OptionListHead);
+
+ if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {
+ DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;
+ }
+ if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {
+ DisplayStatement->Attribute |= HII_DISPLAY_READONLY;
+ }
+
+ //
+ // Initilize the option list in statement.
+ //
+ Link = GetFirstNode (&Statement->OptionListHead);
+ while (!IsNull (&Statement->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Statement->OptionListHead, Link);
+ if ((Option->SuppressExpression != NULL) &&
+ ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
+ continue;
}
+
+ DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));
+ ASSERT (DisplayOption != NULL);
+
+ DisplayOption->ImageId = Option->ImageId;
+ DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE;
+ DisplayOption->OptionOpCode = Option->OpCode;
+ InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);
+ }
+
+ CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));
+
+ //
+ // Some special op code need an extra buffer to save the data.
+ // Such as string, password, orderedlist...
+ //
+ if (Statement->BufferValue != NULL) {
//
- // 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)
+ // Ordered list opcode may not initilized, get default value here.
//
- if (String[Index] == NARROW_CHAR) {
- //
- // Skip to the next character
- //
- Index++;
- IncrementValue = 1;
- } else {
- //
- // Skip to the next character
- //
- Index++;
- IncrementValue = 2;
+ if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {
+ GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);
}
- } while (String[Index] != 0);
+
+ DisplayStatement->CurrentValue.Buffer = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);
+ DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;
+ }
+
+ DisplayStatement->SettingChangedFlag = Statement->ValueChanged;
+
+ //
+ // Get the highlight statement for current form.
+ //
+ if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||
+ ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {
+ gDisplayFormData.HighLightedStatement = DisplayStatement;
+ }
+
+ //
+ // Create the refresh event process function.
+ //
+ if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {
+ CreateRefreshEvent (Statement);
+ }
+
+ //
+ // For RTC type of date/time, set default refresh interval to be 1 second.
+ //
+ if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {
+ Statement->RefreshInterval = 1;
+ }
+
+ //
+ // Create the refresh guid hook event.
+ // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
+ //
+ if ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) {
+ gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
+ }
//
- // Increment by one to include the null-terminator in the size
+ // Save the password check function for later use.
//
- Count++;
+ if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
+ DisplayStatement->PasswordCheck = PasswordCheck;
+ }
+
+ //
+ // Save the validate check question for later use.
+ //
+ if (!IsListEmpty (&Statement->InconsistentListHead)) {
+ DisplayStatement->ValidateQuestion = QuestionCheck;
+ }
- return Count * sizeof (CHAR16);
+ //
+ // If this statement is nest in the subtitle, insert to the host statement.
+ // else insert to the form it belongs to.
+ //
+ if (Statement->InSubtitle) {
+ InsertTailList(&HostDisplayStatement->NestStatementList, &DisplayStatement->DisplayLink);
+ } else {
+ InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
+ }
}
/**
- This function displays the page frame.
+ Process for the refresh interval statement.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
**/
VOID
-DisplayPageFrame (
- IN UI_MENU_SELECTION *Selection
+EFIAPI
+RefreshIntervalProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
)
{
- UINTN Index;
- UINT8 Line;
- UINT8 Alignment;
- CHAR16 Character;
- CHAR16 *Buffer;
- CHAR16 *StrFrontPageBanner;
- UINTN Row;
- EFI_SCREEN_DESCRIPTOR LocalScreen;
- UINT8 RowIdx;
- UINT8 ColumnIdx;
-
- ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR));
- gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow);
- ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND);
-
- if (Selection->Form->ModalForm) {
- return;
+ FORM_BROWSER_STATEMENT *Statement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+
+ if (Statement->RefreshInterval == 0) {
+ continue;
+ }
+
+ UpdateStatement(Statement);
}
- CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gBS->SignalEvent (mValueChangedEvent);
+}
+
+/**
+
+ Make a copy of the global hotkey info.
+
+**/
+VOID
+UpdateHotkeyList (
+ VOID
+ )
+{
+ BROWSER_HOT_KEY *HotKey;
+ BROWSER_HOT_KEY *CopyKey;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gBrowserHotKeyList);
+ while (!IsNull (&gBrowserHotKeyList, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+
+ CopyKey = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);
+ CopyKey->KeyData = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);
+ CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);
+
+ InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
+
+ Link = GetNextNode (&gBrowserHotKeyList, Link);
+ }
+}
+
+/**
+
+ Enum all statement in current form, find all the statement can be display and
+ add to the display form.
+
+**/
+VOID
+AddStatementToDisplayForm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
+ FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement;
+ UINT8 MinRefreshInterval;
+ EFI_EVENT RefreshIntervalEvent;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+ BOOLEAN FormEditable;
+
+ HostDisplayStatement = NULL;
+ MinRefreshInterval = 0;
+ FormEditable = FALSE;
//
- // For now, allocate an arbitrarily long buffer
+ // Process the statement outside the form, these statements are not recognized
+ // by browser core.
//
- Buffer = AllocateZeroPool (0x10000);
- ASSERT (Buffer != NULL);
+ Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
+ while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
+
+ DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (DisplayStatement != NULL);
+ DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
+ DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
+ DisplayStatement->OpCode = Statement->OpCode;
- Character = BOXDRAW_HORIZONTAL;
+ InitializeListHead (&DisplayStatement->NestStatementList);
+ InitializeListHead (&DisplayStatement->OptionListHead);
- for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {
- Buffer[Index] = Character;
+ InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
}
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
+ //
+ // Process the statement in this form.
+ //
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+
//
- // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
+ // This statement can't be show, skip it.
//
- ClearLines (
- LocalScreen.LeftColumn,
- LocalScreen.RightColumn,
- LocalScreen.TopRow,
- FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow,
- BANNER_TEXT | BANNER_BACKGROUND
- );
+ if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
+ continue;
+ }
+
+ DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (DisplayStatement != NULL);
+
//
- // for (Line = 0; Line < BANNER_HEIGHT; Line++) {
+ // Initialize this statement and add it to the display form.
//
- for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {
- //
- // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
- //
- for (Alignment = (UINT8) LocalScreen.LeftColumn;
- Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn;
- Alignment++
- ) {
- RowIdx = (UINT8) (Line - (UINT8) LocalScreen.TopRow);
- ColumnIdx = (UINT8) (Alignment - (UINT8) LocalScreen.LeftColumn);
-
- ASSERT (RowIdx < BANNER_HEIGHT);
- ASSERT (ColumnIdx < BANNER_COLUMNS);
-
- if (gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {
- StrFrontPageBanner = GetToken (
- gBannerData->Banner[RowIdx][ColumnIdx],
- gFrontPageHandle
- );
- } else {
- continue;
- }
+ InitializeDisplayStatement(DisplayStatement, Statement, HostDisplayStatement);
- switch (Alignment - LocalScreen.LeftColumn) {
- case 0:
- //
- // Handle left column
- //
- PrintStringAt (LocalScreen.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);
- break;
-
- case 1:
- //
- // Handle center column
- //
- PrintStringAt (
- LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
- Line,
- StrFrontPageBanner
- );
- break;
+ //
+ // Save the Host statement info.
+ // Host statement may has nest statement follow it.
+ //
+ if (!Statement->InSubtitle) {
+ HostDisplayStatement = DisplayStatement;
+ }
- case 2:
- //
- // Handle right column
- //
- PrintStringAt (
- LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,
- Line,
- StrFrontPageBanner
- );
- break;
- }
+ if (Statement->Storage != NULL) {
+ FormEditable = TRUE;
+ }
- FreePool (StrFrontPageBanner);
- }
+ //
+ // Get the minimal refresh interval value for later use.
+ //
+ if ((Statement->RefreshInterval != 0) &&
+ (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {
+ MinRefreshInterval = Statement->RefreshInterval;
}
}
- ClearLines (
- LocalScreen.LeftColumn,
- LocalScreen.RightColumn,
- LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,
- LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,
- KEYHELP_TEXT | KEYHELP_BACKGROUND
- );
-
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {
- ClearLines (
- LocalScreen.LeftColumn,
- LocalScreen.RightColumn,
- LocalScreen.TopRow,
- LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1,
- TITLE_TEXT | TITLE_BACKGROUND
- );
- //
- // Print Top border line
- // +------------------------------------------------------------------------------+
- // ? ?
- // +------------------------------------------------------------------------------+
- //
- Character = BOXDRAW_DOWN_RIGHT;
-
- PrintChar (Character);
- PrintString (Buffer);
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintChar (Character);
-
- Character = BOXDRAW_VERTICAL;
- for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
- PrintCharAt (LocalScreen.LeftColumn, Row, Character);
- PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
- }
+ //
+ // Create the periodic timer for refresh interval statement.
+ //
+ if (MinRefreshInterval != 0) {
+ Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
+ ASSERT_EFI_ERROR (Status);
+
+ EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
+ ASSERT (EventNode != NULL);
+ EventNode->RefreshEvent = RefreshIntervalEvent;
+ InsertTailList(&mRefreshEventList, &EventNode->Link);
+ }
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
- PrintString (Buffer);
+ //
+ // Update hotkey list field.
+ //
+ if (gBrowserSettingScope == SystemLevel || FormEditable) {
+ UpdateHotkeyList();
+ }
+}
- Character = BOXDRAW_UP_LEFT;
- PrintChar (Character);
+/**
- if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {
- //
- // Print Bottom border line
- // +------------------------------------------------------------------------------+
- // ? ?
- // +------------------------------------------------------------------------------+
- //
- Character = BOXDRAW_DOWN_RIGHT;
- PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);
-
- PrintString (Buffer);
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintChar (Character);
- Character = BOXDRAW_VERTICAL;
- for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
- Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;
- Row++
- ) {
- PrintCharAt (LocalScreen.LeftColumn, Row, Character);
- PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
- }
+ Initialize the SettingChangedFlag variable in the display form.
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
+**/
+VOID
+UpdateDataChangedFlag (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *LocalFormSet;
- PrintString (Buffer);
+ gDisplayFormData.SettingChangedFlag = FALSE;
- Character = BOXDRAW_UP_LEFT;
- PrintChar (Character);
- }
+ if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
}
- FreePool (Buffer);
+ //
+ // Base on the system level to check whether need to show the NV flag.
+ //
+ switch (gBrowserSettingScope) {
+ case SystemLevel:
+ //
+ // Check the maintain list to see whether there is any change.
+ //
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
+ }
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ }
+ break;
+
+ case FormSetLevel:
+ if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
}
-
/**
- Evaluate all expressions in a Form.
- @param FormSet FormSet this Form belongs to.
- @param Form The Form.
+ Initialize the Display form structure data.
- @retval EFI_SUCCESS The expression evaluated successfuly
+**/
+VOID
+InitializeDisplayFormData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
+ gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1;
+ gDisplayFormData.ImageId = 0;
+ gDisplayFormData.AnimationId = 0;
+
+ InitializeListHead (&gDisplayFormData.StatementListHead);
+ InitializeListHead (&gDisplayFormData.StatementListOSF);
+ InitializeListHead (&gDisplayFormData.HotKeyListHead);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_CALLBACK,
+ SetupBrowserEmptyFunction,
+ NULL,
+ &mValueChangedEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+
+ Free the kotkey info saved in form data.
**/
-EFI_STATUS
-EvaluateFormExpressions (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_FORM *Form
+VOID
+FreeHotkeyList (
+ VOID
)
{
- EFI_STATUS Status;
+ BROWSER_HOT_KEY *HotKey;
LIST_ENTRY *Link;
- FORM_EXPRESSION *Expression;
- Link = GetFirstNode (&Form->ExpressionListHead);
- while (!IsNull (&Form->ExpressionListHead, Link)) {
- Expression = FORM_EXPRESSION_FROM_LINK (Link);
- Link = GetNextNode (&Form->ExpressionListHead, Link);
+ while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
+ Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
- if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||
- Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||
- Expression->Type == EFI_HII_EXPRESSION_WRITE ||
- (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {
- //
- // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
- //
- continue;
- }
+ RemoveEntryList (&HotKey->Link);
- Status = EvaluateExpression (FormSet, Form, Expression);
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ FreePool (HotKey->KeyData);
+ FreePool (HotKey->HelpString);
+ FreePool (HotKey);
}
+}
- return EFI_SUCCESS;
+/**
+
+ Update the Display form structure data.
+
+**/
+VOID
+UpdateDisplayFormData (
+ VOID
+ )
+{
+ gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle;
+ gDisplayFormData.FormId = gCurrentSelection->FormId;
+ gDisplayFormData.HiiHandle = gCurrentSelection->Handle;
+ CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
+
+ gDisplayFormData.Attribute = 0;
+ gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
+ gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0;
+
+ gDisplayFormData.FormRefreshEvent = NULL;
+ gDisplayFormData.HighLightedStatement = NULL;
+
+ gDisplayFormData.BrowserStatus = gBrowserStatus;
+ gDisplayFormData.ErrorString = gErrorInfo;
+
+ gBrowserStatus = BROWSER_SUCCESS;
+ gErrorInfo = NULL;
+
+ UpdateDataChangedFlag ();
+
+ AddStatementToDisplayForm ();
}
-/*
-+------------------------------------------------------------------------------+
-? Setup Page ?
-+------------------------------------------------------------------------------+
+/**
+ Free the Display Statement structure data.
+ @param StatementList Point to the statement list which need to be free.
+**/
+VOID
+FreeStatementData (
+ LIST_ENTRY *StatementList
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *OptionLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ DISPLAY_QUESTION_OPTION *Option;
+ //
+ // Free Statements/Questions
+ //
+ while (!IsListEmpty (StatementList)) {
+ Link = GetFirstNode (StatementList);
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ //
+ // Free Options List
+ //
+ while (!IsListEmpty (&Statement->OptionListHead)) {
+ OptionLink = GetFirstNode (&Statement->OptionListHead);
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
+ RemoveEntryList (&Option->Link);
+ FreePool (Option);
+ }
+ //
+ // Free nest statement List
+ //
+ if (!IsListEmpty (&Statement->NestStatementList)) {
+ FreeStatementData(&Statement->NestStatementList);
+ }
+ RemoveEntryList (&Statement->DisplayLink);
+ FreePool (Statement);
+ }
+}
+/**
+ Free the Display form structure data.
+**/
+VOID
+FreeDisplayFormData (
+ VOID
+ )
+{
+ FreeStatementData (&gDisplayFormData.StatementListHead);
+ FreeStatementData (&gDisplayFormData.StatementListOSF);
+
+ FreeRefreshEvent();
+ FreeHotkeyList();
+}
+/**
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ if (Statement->OpCode == DisplayStatement->OpCode) {
+ return Statement;
+ }
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+ }
-+------------------------------------------------------------------------------+
-?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ?
-| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Discard Changes |
-+------------------------------------------------------------------------------+
-*/
+ return NULL;
+}
/**
+ Process the action request in user input.
- Display form and wait for user to select one menu option, then return it.
+ @param Action The user input action request info.
+ @param DefaultId The user input default Id info.
- @param Selection On input, Selection tell setup browser the information
- about the Selection, form and formset to be displayed.
- On output, Selection return the screen item that is selected
- by user.
@retval EFI_SUCESSS This function always return successfully for now.
**/
-EFI_STATUS
-DisplayForm (
- IN OUT UI_MENU_SELECTION *Selection
+EFI_STATUS
+ProcessAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
)
{
- CHAR16 *StringPtr;
- UINT16 MenuItemCount;
- EFI_HII_HANDLE Handle;
- EFI_SCREEN_DESCRIPTOR LocalScreen;
- UINT16 Width;
- UINTN ArrayEntry;
- CHAR16 *OutputString;
- LIST_ENTRY *Link;
- FORM_BROWSER_STATEMENT *Statement;
- UINT16 NumberOfLines;
- EFI_STATUS Status;
- UI_MENU_OPTION *MenuOption;
- UINT16 GlyphWidth;
+ EFI_STATUS Status;
+
+ //
+ // This is caused by use press ESC, and it should not combine with other action type.
+ //
+ if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
+ FindNextMenu (gCurrentSelection, FormLevel);
+ return EFI_SUCCESS;
+ }
- Handle = Selection->Handle;
- MenuItemCount = 0;
- ArrayEntry = 0;
- OutputString = NULL;
+ //
+ // Below is normal hotkey trigged action, these action maybe combine with each other.
+ //
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ }
- UiInitMenu ();
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
+ }
- CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (EFI_ERROR (Status)) {
+ gBrowserStatus = BROWSER_SUBMIT_FAIL;
+ }
+ }
- StringPtr = GetToken (Selection->Form->FormTitle, Handle);
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ gResetRequired = TRUE;
+ }
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {
- if (Selection->Form->ModalForm) {
- gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | EFI_BACKGROUND_BLACK);
- } else {
- gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ //
+ // Form Exit without saving, Similar to ESC Key.
+ // FormSet Exit without saving, Exit SendForm.
+ // System Exit without saving, CallExitHandler and Exit SendForm.
+ //
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
+ FindNextMenu (gCurrentSelection, gBrowserSettingScope);
+ } else if (gBrowserSettingScope == SystemLevel) {
+ if (ExitHandlerFunction != NULL) {
+ ExitHandlerFunction ();
+ }
+ gCurrentSelection->Action = UI_ACTION_EXIT;
}
- PrintStringAt (
- (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,
- LocalScreen.TopRow + 1,
- StringPtr
- );
}
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find HII Handle in the HII database associated with given Device Path.
+
+ If DevicePath is NULL, then ASSERT.
+
+ @param DevicePath Device Path associated with the HII package list
+ handle.
+
+ @retval Handle HII package list Handle associated with the Device
+ Path.
+ @retval NULL Hii Package list handle is not found.
+
+**/
+EFI_HII_HANDLE
+EFIAPI
+DevicePathToHiiHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ UINTN BufferSize;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_HANDLE Handle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+
+ ASSERT (DevicePath != NULL);
+
+ TmpDevicePath = DevicePath;
//
- // Remove Buffer allocated for StringPtr after it has been used.
+ // Locate Device Path Protocol handle buffer
//
- FreePool (StringPtr);
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TmpDevicePath,
+ &DriverHandle
+ );
+ if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
+ return NULL;
+ }
//
- // Evaluate all the Expressions in this Form
+ // Retrieve all HII Handles from HII database
//
- Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form);
+ BufferSize = 0x1000;
+ HiiHandles = AllocatePool (BufferSize);
+ ASSERT (HiiHandles != NULL);
+ Status = mHiiDatabase->ListPackageLists (
+ mHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &BufferSize,
+ HiiHandles
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (HiiHandles);
+ HiiHandles = AllocatePool (BufferSize);
+ ASSERT (HiiHandles != NULL);
+
+ Status = mHiiDatabase->ListPackageLists (
+ mHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &BufferSize,
+ HiiHandles
+ );
+ }
+
if (EFI_ERROR (Status)) {
- return Status;
+ FreePool (HiiHandles);
+ return NULL;
}
- Selection->FormEditable = FALSE;
- Link = GetFirstNode (&Selection->Form->StatementListHead);
- while (!IsNull (&Selection->Form->StatementListHead, Link)) {
- Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ //
+ // Search Hii Handle by Driver Handle
+ //
+ HiiHandle = NULL;
+ HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = mHiiDatabase->GetPackageListHandle (
+ mHiiDatabase,
+ HiiHandles[Index],
+ &Handle
+ );
+ if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
+ HiiHandle = HiiHandles[Index];
+ break;
+ }
+ }
- if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) <= ExpressGrayOut) {
- StringPtr = GetToken (Statement->Prompt, Handle);
- ASSERT (StringPtr != NULL);
+ FreePool (HiiHandles);
+ return HiiHandle;
+}
- Width = GetWidth (Statement, Handle);
+/**
+ Find HII Handle in the HII database associated with given form set guid.
- NumberOfLines = 1;
- ArrayEntry = 0;
- GlyphWidth = 1;
- for (; GetLineByWidth (StringPtr, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&StringPtr[ArrayEntry]) != 0) {
- NumberOfLines++;
- }
+ If FormSetGuid is NULL, then ASSERT.
- FreePool (OutputString);
- }
+ @param ComparingGuid FormSet Guid associated with the HII package list
+ handle.
- //
- // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
- // it in UiFreeMenu.
- //
- MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Selection->Form, Statement, NumberOfLines, MenuItemCount);
- MenuItemCount++;
+ @retval Handle HII package list Handle associated with the Device
+ Path.
+ @retval NULL Hii Package list handle is not found.
+
+**/
+EFI_HII_HANDLE
+FormSetGuidToHiiHandle (
+ EFI_GUID *ComparingGuid
+ )
+{
+ EFI_HII_HANDLE *HiiHandles;
+ UINTN Index;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN BufferSize;
+ UINT32 Offset;
+ UINT32 Offset2;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+
+ ASSERT (ComparingGuid != NULL);
+
+ HiiHandle = NULL;
+ //
+ // Get all the Hii handles
+ //
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ //
+ // Search for formset of each class type
+ //
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status) || HiiPackageList == NULL) {
+ return NULL;
+ }
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ Offset2 = 0;
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
+
+ while (Offset < PackageListLength) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
- if (MenuOption->IsQuestion && !MenuOption->ReadOnly) {
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
//
- // At least one item is not readonly, this Form is considered as editable
+ // Search FormSet in this Form Package
//
- Selection->FormEditable = TRUE;
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset2 < PackageHeader.Length) {
+ OpCodeData = Package + Offset2;
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
+ //
+ // Try to compare against formset GUID
+ //
+ if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
+ HiiHandle = HiiHandles[Index];
+ break;
+ }
+ }
+
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ }
+ }
+ if (HiiHandle != NULL) {
+ break;
}
+ Offset += PackageHeader.Length;
}
-
- Link = GetNextNode (&Selection->Form->StatementListHead, Link);
+
+ FreePool (HiiPackageList);
+ if (HiiHandle != NULL) {
+ break;
+ }
}
- Status = UiDisplayMenu (Selection);
-
- UiFreeMenu ();
+ FreePool (HiiHandles);
- return Status;
+ return HiiHandle;
}
/**
- Initialize the HII String Token to the correct values.
+ check how to process the changed data in current form or form set.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+
+ @param Scope Data save or discard scope, form or formset.
+ @retval TRUE Success process the changed data, will return to the parent form.
+ @retval FALSE Reject to process the changed data, will stay at current form.
**/
-VOID
-InitializeBrowserStrings (
- VOID
+BOOLEAN
+ProcessChangedData (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE Scope
)
{
- gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle);
- gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle);
- gEnterEscapeString = GetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), gHiiHandle);
- gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle);
- gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle);
- gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle);
- gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle);
- gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle);
- gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), 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);
- gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle);
- gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
- gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
- gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
- gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle);
- gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle);
- gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle);
- gSaveChanges = GetToken (STRING_TOKEN (SAVE_CHANGES), gHiiHandle);
- gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);
- gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);
- gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);
- return ;
+ BOOLEAN RetValue;
+
+ RetValue = TRUE;
+ switch (mFormDisplay->ConfirmDataChange()) {
+ case BROWSER_ACTION_DISCARD:
+ DiscardForm (Selection->FormSet, Selection->Form, Scope);
+ break;
+
+ case BROWSER_ACTION_SUBMIT:
+ SubmitForm (Selection->FormSet, Selection->Form, Scope);
+ break;
+
+ case BROWSER_ACTION_NONE:
+ RetValue = FALSE;
+ break;
+
+ default:
+ //
+ // if Invalid value return, process same as BROWSER_ACTION_NONE.
+ //
+ RetValue = FALSE;
+ break;
+ }
+
+ return RetValue;
}
/**
- Free up the resource allocated for all strings required
- by Setup Browser.
+ Find parent formset menu(the first menu which has different formset) for current menu.
+ If not find, just return to the first menu.
+
+ @param Selection The selection info.
**/
VOID
-FreeBrowserStrings (
- VOID
+FindParentFormSet (
+ IN OUT UI_MENU_SELECTION *Selection
)
{
- FreePool (gEnterString);
- FreePool (gEnterCommitString);
- FreePool (gEnterEscapeString);
- FreePool (gEscapeString);
- FreePool (gMoveHighlight);
- FreePool (gMakeSelection);
- FreePool (gDecNumericInput);
- FreePool (gHexNumericInput);
- FreePool (gToggleCheckBox);
- FreePool (gPromptForData);
- FreePool (gPromptForPassword);
- FreePool (gPromptForNewPassword);
- FreePool (gConfirmPassword);
- FreePool (gPassowordInvalid);
- FreePool (gConfirmError);
- FreePool (gPressEnter);
- FreePool (gEmptyString);
- FreePool (gAreYouSure);
- FreePool (gYesResponse);
- FreePool (gNoResponse);
- FreePool (gMiniString);
- FreePool (gPlusString);
- FreePool (gMinusString);
- FreePool (gAdjustNumber);
- FreePool (gSaveChanges);
- FreePool (gOptionMismatch);
- FreePool (gFormSuppress);
- FreePool (gProtocolNotFound);
- return ;
+ FORM_ENTRY_INFO *CurrentMenu;
+ FORM_ENTRY_INFO *ParentMenu;
+
+ CurrentMenu = Selection->CurrentMenu;
+ ParentMenu = UiFindParentMenu(CurrentMenu);
+
+ //
+ // Find a menu which has different formset guid with current.
+ //
+ while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
+ CurrentMenu = ParentMenu;
+ ParentMenu = UiFindParentMenu(CurrentMenu);
+ }
+
+ if (ParentMenu != NULL) {
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
+ Selection->Handle = ParentMenu->HiiHandle;
+ Selection->FormId = ParentMenu->FormId;
+ Selection->QuestionId = ParentMenu->QuestionId;
+ } else {
+ Selection->FormId = CurrentMenu->FormId;
+ Selection->QuestionId = CurrentMenu->QuestionId;
+ }
+
+ Selection->Statement = NULL;
}
/**
- Show all registered HotKey help strings on bottom Rows.
+ Process the goto op code, update the info in the selection structure.
+
+ @param Statement The statement belong to goto op code.
+ @param Selection The selection info.
+ @retval EFI_SUCCESS The menu process successfully.
+ @return Other value if the process failed.
**/
-VOID
-PrintHotKeyHelpString (
- VOID
+EFI_STATUS
+ProcessGotoOpCode (
+ IN OUT FORM_BROWSER_STATEMENT *Statement,
+ IN OUT UI_MENU_SELECTION *Selection
)
{
- UINTN CurrentCol;
- UINTN CurrentRow;
- UINTN BottomRowOfHotKeyHelp;
- UINTN ColumnWidth;
- UINTN Index;
- EFI_SCREEN_DESCRIPTOR LocalScreen;
- LIST_ENTRY *Link;
- BROWSER_HOT_KEY *HotKey;
+ CHAR16 *StringPtr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ FORM_BROWSER_FORM *RefForm;
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+
+ Status = EFI_SUCCESS;
+ StringPtr = NULL;
+ HiiHandle = NULL;
- CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
- ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
- BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;
+ //
+ // Prepare the device path check, get the device path info first.
+ //
+ if (Statement->HiiValue.Value.ref.DevicePath != 0) {
+ StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
+ }
//
- // Calculate total number of Register HotKeys.
+ // Check whether the device path string is a valid string.
//
- Index = 0;
- Link = GetFirstNode (&gBrowserHotKeyList);
- while (!IsNull (&gBrowserHotKeyList, Link)) {
- HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
- //
- // Help string can't exceed ColumnWidth. One Row will show three Help information.
- //
- if (StrLen (HotKey->HelpString) > ColumnWidth) {
- HotKey->HelpString[ColumnWidth] = L'\0';
+ if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {
+ if (Selection->Form->ModalForm) {
+ return Status;
}
+
//
- // Calculate help information Column and Row.
+ // Goto another Hii Package list
//
- if ((Index % 3) != 2) {
- CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth;
+ if (mPathFromText != NULL) {
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
+ if (DevicePath != NULL) {
+ HiiHandle = DevicePathToHiiHandle (DevicePath);
+ FreePool (DevicePath);
+ }
+ FreePool (StringPtr);
} else {
- CurrentCol = LocalScreen.LeftColumn + 2;
+ //
+ // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
+ //
+ gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND;
+ FreePool (StringPtr);
+ return Status;
+ }
+
+ if (HiiHandle != Selection->Handle) {
+ //
+ // Goto another Formset, check for uncommitted data
+ //
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
+ if (!ProcessChangedData(Selection, FormSetLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ Selection->Handle = HiiHandle;
+ if (Selection->Handle == NULL) {
+ //
+ // If target Hii Handle not found, exit current formset.
+ //
+ FindParentFormSet(Selection);
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {
+ if (Selection->Form->ModalForm) {
+ return Status;
+ }
+ if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
+ //
+ // Goto another Formset, check for uncommitted data
+ //
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
+ if (!ProcessChangedData(Selection, FormSetLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
+ if (Selection->Handle == NULL) {
+ //
+ // If target Hii Handle not found, exit current formset.
+ //
+ FindParentFormSet(Selection);
+ return EFI_SUCCESS;
}
- CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
- //
- // Print HotKey help string on bottom Row.
- //
- PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString);
+ CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (Statement->HiiValue.Value.ref.FormId != 0) {
//
- // Get Next Hot Key.
+ // Goto another Form, check for uncommitted data
//
- Link = GetNextNode (&gBrowserHotKeyList, Link);
- Index ++;
+ if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
+ if (!ProcessChangedData (Selection, FormLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
+ if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
+ if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
+ //
+ // Form is suppressed.
+ //
+ gBrowserStatus = BROWSER_FORM_SUPPRESS;
+ return EFI_SUCCESS;
+ }
+ }
+
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
}
-
- return;
+
+ return Status;
}
+
/**
- Update key's help imformation.
+ Process Question Config.
- @param Selection Tell setup browser the information about the Selection
- @param MenuOption The Menu option
- @param Selected Whether or not a tag be selected
+ @param Selection The UI menu selection.
+ @param Question The Question to be peocessed.
+
+ @retval EFI_SUCCESS Question Config process success.
+ @retval Other Question Config process fail.
**/
-VOID
-UpdateKeyHelp (
- IN UI_MENU_SELECTION *Selection,
- IN UI_MENU_OPTION *MenuOption,
- IN BOOLEAN Selected
+EFI_STATUS
+ProcessQuestionConfig (
+ IN UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_STATEMENT *Question
)
{
- UINTN SecCol;
- UINTN ThdCol;
- UINTN LeftColumnOfHelp;
- UINTN RightColumnOfHelp;
- UINTN TopRowOfHelp;
- UINTN BottomRowOfHelp;
- UINTN StartColumnOfHelp;
- EFI_SCREEN_DESCRIPTOR LocalScreen;
- FORM_BROWSER_STATEMENT *Statement;
+ EFI_STATUS Status;
+ CHAR16 *ConfigResp;
+ CHAR16 *Progress;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+ if (Question->QuestionConfig == 0) {
+ return EFI_SUCCESS;
+ }
- if (Selection->Form->ModalForm) {
- return;
+ //
+ // Get <ConfigResp>
+ //
+ ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
+ if (ConfigResp == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Send config to Configuration Driver
+ //
+ ConfigAccess = Selection->FormSet->ConfigAccess;
+ if (ConfigAccess == NULL) {
+ return EFI_UNSUPPORTED;
}
+ Status = ConfigAccess->RouteConfig (
+ ConfigAccess,
+ ConfigResp,
+ &Progress
+ );
- CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ return Status;
+}
- SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
- ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3 * 2;
+/**
- StartColumnOfHelp = LocalScreen.LeftColumn + 2;
- LeftColumnOfHelp = LocalScreen.LeftColumn + 1;
- RightColumnOfHelp = LocalScreen.RightColumn - 2;
- TopRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
- BottomRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;
+ Process the user input data.
- Statement = MenuOption->ThisTag;
- switch (Statement->Operand) {
- 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:
- ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+ @param UserInput The user input data.
+ @param ChangeHighlight Whether need to change the highlight statement.
+
+ @retval EFI_SUCESSS This function always return successfully for now.
+
+**/
+EFI_STATUS
+ProcessUserInput (
+ IN USER_INPUT *UserInput,
+ IN BOOLEAN ChangeHighlight
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_STATEMENT *Statement;
- if (!Selected) {
+ Status = EFI_SUCCESS;
+
+ //
+ // When Exit from FormDisplay function, one of the below two cases must be true.
+ //
+ ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
+
+ //
+ // Remove the last highligh question id, this id will update when show next form.
+ //
+ gCurrentSelection->QuestionId = 0;
+
+ //
+ // First process the Action field in USER_INPUT.
+ //
+ if (UserInput->Action != 0) {
+ Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Clear the highlight info.
+ //
+ gCurrentSelection->Statement = NULL;
+
+ if (UserInput->SelectedStatement != NULL) {
+ Statement = GetBrowserStatement(UserInput->SelectedStatement);
+ ASSERT (Statement != NULL);
+ //
+ // Save the current highlight menu in the menu history data.
+ // which will be used when later browse back to this form.
+ //
+ gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
//
- // On system setting, HotKey will show on every form.
+ // For statement like text, actio, it not has question id.
+ // So use FakeQuestionId to save the question.
//
- if (gBrowserSettingScope == SystemLevel ||
- (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {
- PrintHotKeyHelpString ();
+ if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
+ mCurFakeQestId = Statement->FakeQuestionId;
+ } else {
+ mCurFakeQestId = 0;
}
+ }
+ } else {
+ Statement = GetBrowserStatement(UserInput->SelectedStatement);
+ ASSERT (Statement != NULL);
- if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {
- PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
- }
+ gCurrentSelection->Statement = Statement;
- if ((Statement->Operand == EFI_IFR_DATE_OP) ||
- (Statement->Operand == EFI_IFR_TIME_OP)) {
- PrintAt (
- StartColumnOfHelp,
- BottomRowOfHelp,
- L"%c%c%c%c%s",
- ARROW_UP,
- ARROW_DOWN,
- ARROW_RIGHT,
- ARROW_LEFT,
- gMoveHighlight
- );
- PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
- PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);
+ if (ChangeHighlight) {
+ //
+ // This question is the current user select one,record it and later
+ // show it as the highlight question.
+ //
+ gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
+ //
+ // For statement like text, actio, it not has question id.
+ // So use FakeQuestionId to save the question.
+ //
+ if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
+ mCurFakeQestId = Statement->FakeQuestionId;
} else {
- PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
- if (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0) {
- PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);
- }
- PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
+ mCurFakeQestId = 0;
}
- } else {
- PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);
+ }
+ switch (Statement->Operand) {
+ case EFI_IFR_REF_OP:
+ Status = ProcessGotoOpCode(Statement, gCurrentSelection);
+ break;
+
+ case EFI_IFR_ACTION_OP:
//
- // If it is a selected numeric with manual input, display different message
+ // Process the Config string <ConfigResp>
//
- if ((Statement->Operand == EFI_IFR_NUMERIC_OP) ||
- (Statement->Operand == EFI_IFR_DATE_OP) ||
- (Statement->Operand == EFI_IFR_TIME_OP)) {
- PrintStringAt (
- SecCol,
- TopRowOfHelp,
- ((Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput
- );
- } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) {
- PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
- }
+ Status = ProcessQuestionConfig (gCurrentSelection, Statement);
+ break;
+
+ case EFI_IFR_RESET_BUTTON_OP:
+ //
+ // Reset Question to default value specified by DefaultId
+ //
+ Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);
+ break;
- if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) {
- PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);
- PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);
- }
+ default:
+ switch (Statement->Operand) {
+ case EFI_IFR_STRING_OP:
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
+ FreePool (UserInput->InputValue.Buffer);
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ if (UserInput->InputValue.Buffer == NULL) {
+ //
+ // User not input new password, just return.
+ //
+ break;
+ }
- PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
+ FreePool (UserInput->InputValue.Buffer);
+ //
+ // Two password match, send it to Configuration Driver
+ //
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
+ PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
+ //
+ // Clean the value after saved it.
+ //
+ ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
+ HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
+ } else {
+ SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
+ break;
+
+ default:
+ CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
+ break;
+ }
+ if (Statement->Operand != EFI_IFR_PASSWORD_OP) {
+ SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
+ }
+ break;
}
- break;
+ }
+
+ return Status;
+}
+
+/**
+
+ Display form and wait for user to select one menu option, then return it.
+
+ @retval EFI_SUCESSS This function always return successfully for now.
+
+**/
+EFI_STATUS
+DisplayForm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ USER_INPUT UserInput;
+ FORM_ENTRY_INFO *CurrentMenu;
+ BOOLEAN ChangeHighlight;
- case EFI_IFR_CHECKBOX_OP:
- ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+ ZeroMem (&UserInput, sizeof (USER_INPUT));
+ //
+ // Update the menu history data.
+ //
+ CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
+ if (CurrentMenu == NULL) {
//
- // On system setting, HotKey will show on every form.
+ // Current menu not found, add it to the menu tree
//
- if (gBrowserSettingScope == SystemLevel ||
- (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {
- PrintHotKeyHelpString ();
- }
- if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {
- PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
- }
-
- PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
- PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);
- break;
+ CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
+ gCurrentSelection->FormId, gCurrentSelection->QuestionId);
+ ASSERT (CurrentMenu != NULL);
+ }
+ gCurrentSelection->CurrentMenu = CurrentMenu;
- case EFI_IFR_REF_OP:
- case EFI_IFR_PASSWORD_OP:
- case EFI_IFR_STRING_OP:
- case EFI_IFR_TEXT_OP:
- case EFI_IFR_ACTION_OP:
- case EFI_IFR_RESET_BUTTON_OP:
- case EFI_IFR_SUBTITLE_OP:
- ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+ //
+ // Find currrent highlight statement.
+ //
+ if (gCurrentSelection->QuestionId == 0) {
+ //
+ // Highlight not specified, fetch it from cached menu
+ //
+ gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
+ }
- if (!Selected) {
- //
- // On system setting, HotKey will show on every form.
- //
- if (gBrowserSettingScope == SystemLevel ||
- (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {
- PrintHotKeyHelpString ();
- }
- if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {
- PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
- }
+ //
+ // Evaluate all the Expressions in this Form
+ //
+ Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
- PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
- if (Statement->Operand != EFI_IFR_TEXT_OP && Statement->Operand != EFI_IFR_SUBTITLE_OP) {
- PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
- }
- } else {
- if (Statement->Operand != EFI_IFR_REF_OP) {
- PrintStringAt (
- (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2,
- BottomRowOfHelp,
- gEnterCommitString
- );
- PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);
- }
- }
- break;
+ UpdateDisplayFormData ();
- default:
- break;
+ //
+ // Three possible status maybe return.
+ //
+ // EFI_INVALID_PARAMETER: The input dimension info is not valid.
+ // EFI_NOT_FOUND: The input value for oneof/orderedlist opcode is not valid
+ // and an valid value has return.
+ // EFI_SUCCESS: Success shows form and get user input in UserInput paramenter.
+ //
+ Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
+ if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
+ FreeDisplayFormData();
+ return Status;
}
+
+ //
+ // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.
+ // in this case, browser need to change the highlight menu.
+ // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist
+ // opcode and new valid value has return, browser core need to adjust
+ // value for this opcode and shows this form again.
+ //
+ ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);
+
+ Status = ProcessUserInput (&UserInput, ChangeHighlight);
+
+ FreeDisplayFormData();
+
+ return Status;
}
/**
@@ -920,60 +1715,136 @@ FormUpdateNotify ( }
/**
- check whether the formset need to update the NV.
+ Update the NV flag info for this form set.
@param FormSet FormSet data structure.
- @retval TRUE Need to update the NV.
- @retval FALSE No need to update the NV.
**/
-BOOLEAN
-IsNvUpdateRequired (
+BOOLEAN
+IsNvUpdateRequiredForFormSet (
IN FORM_BROWSER_FORMSET *FormSet
)
{
LIST_ENTRY *Link;
FORM_BROWSER_FORM *Form;
+ BOOLEAN RetVal;
+
+ //
+ // Not finished question initialization, return FALSE.
+ //
+ if (!FormSet->QuestionInited) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
Link = GetFirstNode (&FormSet->FormListHead);
while (!IsNull (&FormSet->FormListHead, Link)) {
Form = FORM_BROWSER_FORM_FROM_LINK (Link);
- if (Form->NvUpdateRequired ) {
- return TRUE;
+ RetVal = IsNvUpdateRequiredForForm(Form);
+ if (RetVal) {
+ break;
}
Link = GetNextNode (&FormSet->FormListHead, Link);
}
+ return RetVal;
+}
+
+/**
+ Update the NvUpdateRequired flag for a form.
+
+ @param Form Form data structure.
+
+**/
+BOOLEAN
+IsNvUpdateRequiredForForm (
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Statement->ValueChanged) {
+ return TRUE;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
return FALSE;
}
/**
- check whether the formset need to update the NV.
+ Check whether the storage data for current form set is changed.
- @param FormSet FormSet data structure.
- @param SetValue Whether set new value or clear old value.
+ @param FormSet FormSet data structure.
+ @retval TRUE Data is changed.
+ @retval FALSE Data is not changed.
**/
-VOID
-UpdateNvInfoInForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN BOOLEAN SetValue
+BOOLEAN
+IsStorageDataChangedForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
)
{
LIST_ENTRY *Link;
- FORM_BROWSER_FORM *Form;
-
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ FORMSET_STORAGE *Storage;
+ BROWSER_STORAGE *BrowserStorage;
+ CHAR16 *ConfigRespNew;
+ CHAR16 *ConfigRespOld;
+ BOOLEAN RetVal;
- Form->NvUpdateRequired = SetValue;
+ RetVal = FALSE;
+ ConfigRespNew = NULL;
+ ConfigRespOld = NULL;
- Link = GetNextNode (&FormSet->FormListHead, Link);
+ //
+ // Request current settings from Configuration Driver
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ BrowserStorage = Storage->BrowserStorage;
+
+ if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ if (Storage->ElementCount == 0) {
+ continue;
+ }
+
+ StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE);
+ StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE);
+ ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL);
+
+ if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) {
+ RetVal = TRUE;
+ }
+
+ FreePool (ConfigRespNew);
+ ConfigRespNew = NULL;
+
+ FreePool (ConfigRespOld);
+ ConfigRespOld = NULL;
+
+ if (RetVal) {
+ break;
+ }
}
+
+ return RetVal;
}
+
/**
Find menu which will show next time.
@@ -981,170 +1852,92 @@ UpdateNvInfoInForm ( about the Selection, form and formset to be displayed.
On output, Selection return the screen item that is selected
by user.
- @param Repaint Whether need to repaint the menu.
- @param NewLine Whether need to show at new line.
+ @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
+ else, we need to exit current formset.
- @retval TRUE Need return.
- @retval FALSE No need to return.
+ @retval TRUE Exit current form.
+ @retval FALSE User press ESC and keep in current form.
**/
BOOLEAN
FindNextMenu (
- IN OUT UI_MENU_SELECTION *Selection,
- IN BOOLEAN *Repaint,
- IN BOOLEAN *NewLine
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE SettingLevel
)
{
- UI_MENU_LIST *CurrentMenu;
- CHAR16 YesResponse;
- CHAR16 NoResponse;
- EFI_INPUT_KEY Key;
- BROWSER_SETTING_SCOPE Scope;
+ FORM_ENTRY_INFO *CurrentMenu;
+ FORM_ENTRY_INFO *ParentMenu;
+ BROWSER_SETTING_SCOPE Scope;
CurrentMenu = Selection->CurrentMenu;
+ ParentMenu = NULL;
+ Scope = FormSetLevel;
- if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) {
+ if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {
//
// we have a parent, so go to the parent menu
//
- if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {
- //
- // The parent menu and current menu are in the same formset
- //
- Selection->Action = UI_ACTION_REFRESH_FORM;
- Scope = FormLevel;
- } else {
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
- CopyMem (&Selection->FormSetGuid, &CurrentMenu->Parent->FormSetGuid, sizeof (EFI_GUID));
- Selection->Handle = CurrentMenu->Parent->HiiHandle;
- Scope = FormSetLevel;
- }
-
- //
- // Form Level Check whether the data is changed.
- //
- if ((gBrowserSettingScope == FormLevel && Selection->Form->NvUpdateRequired) ||
- (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequired(Selection->FormSet) && Scope == FormSetLevel)) {
- gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-
- YesResponse = gYesResponse[0];
- NoResponse = gNoResponse[0];
-
- //
- // If NV flag is up, prompt user
- //
- do {
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);
- } while
- (
- (Key.ScanCode != SCAN_ESC) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
- );
-
- if (Key.ScanCode == SCAN_ESC) {
+ if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
+ if (SettingLevel == FormSetLevel) {
//
- // User hits the ESC key, Ingore.
+ // Find a menu which has different formset guid with current.
//
- if (Repaint != NULL) {
- *Repaint = TRUE;
- }
- if (NewLine != NULL) {
- *NewLine = TRUE;
+ while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
+ CurrentMenu = ParentMenu;
+ if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {
+ break;
+ }
}
- Selection->Action = UI_ACTION_NONE;
- return FALSE;
- }
-
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
- //
- // If the user hits the YesResponse key
- //
- SubmitForm (Selection->FormSet, Selection->Form, Scope);
+ if (ParentMenu != NULL) {
+ Scope = FormSetLevel;
+ }
} else {
- //
- // If the user hits the NoResponse key
- //
- DiscardForm (Selection->FormSet, Selection->Form, Scope);
+ Scope = FormLevel;
}
+ } else {
+ Scope = FormSetLevel;
}
-
- Selection->Statement = NULL;
-
- Selection->FormId = CurrentMenu->Parent->FormId;
- Selection->QuestionId = CurrentMenu->Parent->QuestionId;
-
- //
- // Clear highlight record for this menu
- //
- CurrentMenu->QuestionId = 0;
- return FALSE;
- }
-
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
- //
- // We never exit FrontPage, so skip the ESC
- //
- Selection->Action = UI_ACTION_NONE;
- return FALSE;
}
//
- // We are going to leave current FormSet, so check uncommited data in this FormSet
+ // Form Level Check whether the data is changed.
//
- if (gBrowserSettingScope != SystemLevel && IsNvUpdateRequired(Selection->FormSet)) {
- gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-
- YesResponse = gYesResponse[0];
- NoResponse = gNoResponse[0];
-
- //
- // If NV flag is up, prompt user
- //
- do {
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);
- } while
- (
- (Key.ScanCode != SCAN_ESC) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
- );
-
- if (Key.ScanCode == SCAN_ESC) {
- //
- // User hits the ESC key
- //
- if (Repaint != NULL) {
- *Repaint = TRUE;
- }
-
- if (NewLine != NULL) {
- *NewLine = TRUE;
- }
-
- Selection->Action = UI_ACTION_NONE;
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
+ (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
+ if (!ProcessChangedData(Selection, Scope)) {
return FALSE;
}
+ }
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
- //
- // If the user hits the YesResponse key
- //
- SubmitForm (Selection->FormSet, Selection->Form, FormSetLevel);
+ if (ParentMenu != NULL) {
+ //
+ // ParentMenu is found. Then, go to it.
+ //
+ if (Scope == FormLevel) {
+ Selection->Action = UI_ACTION_REFRESH_FORM;
} else {
- //
- // If the user hits the NoResponse key
- //
- DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel);
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
+ Selection->Handle = ParentMenu->HiiHandle;
}
- }
- Selection->Statement = NULL;
- if (CurrentMenu != NULL) {
+ Selection->Statement = NULL;
+
+ Selection->FormId = ParentMenu->FormId;
+ Selection->QuestionId = ParentMenu->QuestionId;
+
+ //
+ // Clear highlight record for this menu
+ //
CurrentMenu->QuestionId = 0;
+ return FALSE;
}
+ //
+ // Current in root page, exit the SendForm
+ //
Selection->Action = UI_ACTION_EXIT;
+
return TRUE;
}
@@ -1246,17 +2039,17 @@ ProcessCallBackFunction ( case EFI_BROWSER_ACTION_REQUEST_RESET:
DiscardFormIsRequired = TRUE;
gResetRequired = TRUE;
- Selection->Action = UI_ACTION_EXIT;
+ NeedExit = TRUE;
break;
case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
SubmitFormIsRequired = TRUE;
- Selection->Action = UI_ACTION_EXIT;
+ NeedExit = TRUE;
break;
case EFI_BROWSER_ACTION_REQUEST_EXIT:
DiscardFormIsRequired = TRUE;
- Selection->Action = UI_ACTION_EXIT;
+ NeedExit = TRUE;
break;
case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
@@ -1267,7 +2060,7 @@ ProcessCallBackFunction ( case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
DiscardFormIsRequired = TRUE;
- SettingLevel = FormLevel;
+ SettingLevel = FormLevel;
NeedExit = TRUE;
break;
@@ -1320,7 +2113,7 @@ ProcessCallBackFunction ( }
if (NeedExit) {
- FindNextMenu (Selection, NULL, NULL);
+ FindNextMenu (Selection, SettingLevel);
}
return Status;
@@ -1400,9 +2193,7 @@ SetupBrowser ( EFI_HANDLE NotifyHandle;
FORM_BROWSER_STATEMENT *Statement;
EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
- EFI_INPUT_KEY Key;
- gMenuRefreshHead = NULL;
ConfigAccess = Selection->FormSet->ConfigAccess;
//
@@ -1423,21 +2214,17 @@ SetupBrowser ( //
// Initialize current settings of Questions in this FormSet
//
- Status = InitializeCurrentSetting (Selection->FormSet);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
+ InitializeCurrentSetting (Selection->FormSet);
//
- // Update gOldFormSet on maintain back up FormSet list.
- // And, make gOldFormSet point to current FormSet.
+ // Initilize Action field.
//
- if (gOldFormSet != NULL) {
- RemoveEntryList (&gOldFormSet->Link);
- DestroyFormSet (gOldFormSet);
- }
- gOldFormSet = Selection->FormSet;
- InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link);
+ Selection->Action = UI_ACTION_REFRESH_FORM;
+
+ //
+ // Clean the mCurFakeQestId value is formset refreshed.
+ //
+ mCurFakeQestId = 0;
do {
//
@@ -1480,10 +2267,7 @@ SetupBrowser ( //
// Form is suppressed.
//
- do {
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
+ gBrowserStatus = BROWSER_FORM_SUPPRESS;
Status = EFI_NOT_FOUND;
goto Done;
}
@@ -1498,7 +2282,6 @@ SetupBrowser ( ((Selection->Handle != mCurrentHiiHandle) ||
(!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
(Selection->FormId != mCurrentFormId))) {
-
//
// Keep current form information
//
@@ -1512,12 +2295,6 @@ SetupBrowser ( }
//
- // EXIT requests to close form.
- //
- if (Selection->Action == UI_ACTION_EXIT) {
- goto Done;
- }
- //
// IFR is updated during callback of open form, force to reparse the IFR binary
//
if (mHiiPackageListUpdated) {
@@ -1536,12 +2313,6 @@ SetupBrowser ( }
//
- // EXIT requests to close form.
- //
- if (Selection->Action == UI_ACTION_EXIT) {
- goto Done;
- }
- //
// IFR is updated during callback of read value, force to reparse the IFR binary
//
if (mHiiPackageListUpdated) {
@@ -1551,14 +2322,9 @@ SetupBrowser ( }
//
- // Displays the Header and Footer borders
- //
- DisplayPageFrame (Selection);
-
- //
// Display form
//
- Status = DisplayForm (Selection);
+ Status = DisplayForm ();
if (EFI_ERROR (Status)) {
goto Done;
}
@@ -1568,20 +2334,16 @@ SetupBrowser ( //
Statement = Selection->Statement;
if (Statement != NULL) {
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) {
- gResetRequired = TRUE;
- }
-
if ((ConfigAccess != NULL) &&
((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
(Statement->Operand != EFI_IFR_PASSWORD_OP)) {
- Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
- if (Statement->Operand == EFI_IFR_REF_OP && Selection->Action != UI_ACTION_EXIT) {
+ Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
+ if (Statement->Operand == EFI_IFR_REF_OP) {
//
// Process dynamic update ref opcode.
//
if (!EFI_ERROR (Status)) {
- Status = ProcessGotoOpCode(Statement, Selection, NULL, NULL);
+ Status = ProcessGotoOpCode(Statement, Selection);
}
//
@@ -1603,6 +2365,27 @@ SetupBrowser ( }
//
+ // Check whether Exit flag is TRUE.
+ //
+ if (gExitRequired) {
+ switch (gBrowserSettingScope) {
+ case SystemLevel:
+ Selection->Action = UI_ACTION_EXIT;
+ break;
+
+ case FormSetLevel:
+ case FormLevel:
+ FindNextMenu (Selection, gBrowserSettingScope);
+ break;
+
+ default:
+ break;
+ }
+
+ gExitRequired = FALSE;
+ }
+
+ //
// Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
// for each question with callback flag.
//
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index ed904161b6..c4dd18a04f 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -26,13 +26,21 @@ SETUP_DRIVER_PRIVATE_DATA mPrivateData = { RegisterHotKey,
RegiserExitHandler,
SaveReminder
+ },
+ {
+ BROWSER_EXTENSION2_VERSION_1,
+ SetScope,
+ RegisterHotKey,
+ RegiserExitHandler,
+ IsBrowserDataModified,
+ ExecuteAction,
}
};
EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
-EFI_HII_STRING_PROTOCOL *mHiiString;
EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
+EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
UINTN gBrowserContextCount = 0;
LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
@@ -40,153 +48,261 @@ LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFor LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
-BANNER_DATA *gBannerData;
-EFI_HII_HANDLE gFrontPageHandle;
-UINTN gClassOfVfr;
-UINTN gFunctionKeySetting;
BOOLEAN gResetRequired;
-EFI_HII_HANDLE gHiiHandle;
-UINT16 gDirection;
-EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+BOOLEAN gExitRequired;
BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
BOOLEAN mBrowserScopeFirstSet = TRUE;
EXIT_HANDLER ExitHandlerFunction = NULL;
-UINTN gFooterHeight;
//
// Browser Global Strings
//
-CHAR16 *gSaveFailed;
-CHAR16 *gDiscardFailed;
-CHAR16 *gDefaultFailed;
-CHAR16 *gEnterString;
-CHAR16 *gEnterCommitString;
-CHAR16 *gEnterEscapeString;
-CHAR16 *gEscapeString;
-CHAR16 *gMoveHighlight;
-CHAR16 *gMakeSelection;
-CHAR16 *gDecNumericInput;
-CHAR16 *gHexNumericInput;
-CHAR16 *gToggleCheckBox;
-CHAR16 *gPromptForData;
-CHAR16 *gPromptForPassword;
-CHAR16 *gPromptForNewPassword;
-CHAR16 *gConfirmPassword;
-CHAR16 *gConfirmError;
-CHAR16 *gPassowordInvalid;
-CHAR16 *gPressEnter;
CHAR16 *gEmptyString;
-CHAR16 *gAreYouSure;
-CHAR16 *gYesResponse;
-CHAR16 *gNoResponse;
-CHAR16 *gMiniString;
-CHAR16 *gPlusString;
-CHAR16 *gMinusString;
-CHAR16 *gAdjustNumber;
-CHAR16 *gSaveChanges;
-CHAR16 *gOptionMismatch;
-CHAR16 *gFormSuppress;
-CHAR16 *gProtocolNotFound;
CHAR16 *mUnknownString = L"!";
-CHAR16 gPromptBlockWidth;
-CHAR16 gOptionBlockWidth;
-CHAR16 gHelpBlockWidth;
-
EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
EFI_GUID gSetupBrowserGuid = {
0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}
};
FORM_BROWSER_FORMSET *gOldFormSet = NULL;
+extern UINT32 gBrowserStatus;
+extern CHAR16 *gErrorInfo;
+extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
+
+/**
+ Create a menu with specified formset GUID and form ID, and add it as a child
+ of the given parent menu.
+
+ @param HiiHandle Hii handle related to this formset.
+ @param FormSetGuid The Formset Guid of menu to be added.
+ @param FormId The Form ID of menu to be added.
+ @param QuestionId The question id of this menu to be added.
+
+ @return A pointer to the newly added menu or NULL if memory is insufficient.
+
+**/
+FORM_ENTRY_INFO *
+UiAddMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId,
+ IN UINT16 QuestionId
+ )
+{
+ FORM_ENTRY_INFO *MenuList;
+
+ MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
+ if (MenuList == NULL) {
+ return NULL;
+ }
+
+ MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;
+
+ MenuList->HiiHandle = HiiHandle;
+ CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
+ MenuList->FormId = FormId;
+ MenuList->QuestionId = QuestionId;
-FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {
//
- // Boot Manager
+ // If parent is not specified, it is the root Form of a Formset
//
- {
- {
- 0x847bc3fe,
- 0xb974,
- 0x446d,
- {
- 0x94,
- 0x49,
- 0x5a,
- 0xd5,
- 0x41,
- 0x2e,
- 0x99,
- 0x3b
+ InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
+
+ return MenuList;
+}
+
+/**
+ Return the form id for the input hiihandle and formset.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+
+ @return First form's id for this form set.
+
+**/
+EFI_FORM_ID
+GetFirstFormId (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+
+ Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ return Form->FormId;
+}
+
+/**
+ Search Menu with given FormSetGuid and FormId in all cached menu list.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+ @param FormId The Form ID of menu to search.
+
+ @return A pointer to menu found or NULL if not found.
+
+**/
+FORM_ENTRY_INFO *
+UiFindMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_ENTRY_INFO *MenuList;
+ FORM_ENTRY_INFO *RetMenu;
+ EFI_FORM_ID FirstFormId;
+
+ RetMenu = NULL;
+
+ Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
+ while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
+ Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);
+
+ //
+ // If already find the menu, free the menus behind it.
+ //
+ if (RetMenu != NULL) {
+ RemoveEntryList (&MenuList->Link);
+ FreePool (MenuList);
+ continue;
+ }
+
+ //
+ // Find the same FromSet.
+ //
+ if (MenuList->HiiHandle == HiiHandle) {
+ if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {
+ //
+ // FormSetGuid is not specified.
+ //
+ RetMenu = MenuList;
+ } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {
+ if (MenuList->FormId == FormId) {
+ RetMenu = MenuList;
+ } else if (FormId == 0 || MenuList->FormId == 0 ) {
+ FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);
+ if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {
+ RetMenu = MenuList;
+ }
+ }
}
- },
- NONE_FUNCTION_KEY_SETTING
- },
+ }
+ }
+
+ return RetMenu;
+}
+
+/**
+ Find parent menu for current menu.
+
+ @param CurrentMenu Current Menu
+
+ @retval The parent menu for current menu.
+**/
+FORM_ENTRY_INFO *
+UiFindParentMenu (
+ IN FORM_ENTRY_INFO *CurrentMenu
+ )
+{
+ FORM_ENTRY_INFO *ParentMenu;
+
+ ParentMenu = NULL;
+ if (CurrentMenu->Link.BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
+ ParentMenu = FORM_ENTRY_INFO_FROM_LINK (CurrentMenu->Link.BackLink);
+ }
+
+ return ParentMenu;
+}
+
+/**
+ Free Menu list linked list.
+
+ @param MenuListHead One Menu list point in the menu list.
+
+**/
+VOID
+UiFreeMenuList (
+ LIST_ENTRY *MenuListHead
+ )
+{
+ FORM_ENTRY_INFO *MenuList;
+
+ while (!IsListEmpty (MenuListHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ FreePool (MenuList);
+ }
+}
+
+/**
+ Load all hii formset to the browser.
+
+**/
+VOID
+LoadAllHiiFormset (
+ VOID
+ )
+{
+ FORM_BROWSER_FORMSET *LocalFormSet;
+ EFI_HII_HANDLE *HiiHandles;
+ UINTN Index;
+ EFI_GUID ZeroGuid;
+ EFI_STATUS Status;
+
//
- // Device Manager
+ // Get all the Hii handles
//
- {
- {
- 0x3ebfa8e6,
- 0x511d,
- 0x4b5b,
- {
- 0xa9,
- 0x5f,
- 0xfb,
- 0x38,
- 0x26,
- 0xf,
- 0x1c,
- 0x27
- }
- },
- NONE_FUNCTION_KEY_SETTING
- },
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
//
- // BMM FormSet.
+ // Search for formset of each class type
//
- {
- {
- 0x642237c7,
- 0x35d4,
- 0x472d,
- {
- 0x83,
- 0x65,
- 0x12,
- 0xe0,
- 0xcc,
- 0xf2,
- 0x7a,
- 0x22
- }
- },
- NONE_FUNCTION_KEY_SETTING
- },
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ //
+ // Check HiiHandles[Index] does exist in global maintain list.
+ //
+ if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
+ continue;
+ }
+
+ //
+ // Initilize FormSet Setting
+ //
+ LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
+ ASSERT (LocalFormSet != NULL);
+ ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
+ Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
+ if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
+ DestroyFormSet (LocalFormSet);
+ continue;
+ }
+ InitializeCurrentSetting (LocalFormSet);
+
+ //
+ // Initilize Questions' Value
+ //
+ Status = LoadFormSetConfig (NULL, LocalFormSet);
+ if (EFI_ERROR (Status)) {
+ DestroyFormSet (LocalFormSet);
+ continue;
+ }
+ }
+
//
- // BMM File Explorer FormSet.
+ // Free resources, and restore gOldFormSet and gClassOfVfr
//
- {
- {
- 0x1f2d63e1,
- 0xfebd,
- 0x4dc7,
- {
- 0x9c,
- 0xc5,
- 0xba,
- 0x2b,
- 0x1c,
- 0xef,
- 0x9c,
- 0x5b
- }
- },
- NONE_FUNCTION_KEY_SETTING
- },
-};
+ FreePool (HiiHandles);
+}
/**
This is the routine which an external caller uses to direct the browser
@@ -229,26 +345,14 @@ SendForm ( UI_MENU_SELECTION *Selection;
UINTN Index;
FORM_BROWSER_FORMSET *FormSet;
- LIST_ENTRY *Link;
+ FORM_ENTRY_INFO *MenuList;
//
- // Calculate total number of Register HotKeys.
+ // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.
//
- Index = 0;
- Link = GetFirstNode (&gBrowserHotKeyList);
- while (!IsNull (&gBrowserHotKeyList, Link)) {
- Link = GetNextNode (&gBrowserHotKeyList, Link);
- Index ++;
+ if (mFormDisplay == NULL) {
+ return EFI_UNSUPPORTED;
}
- //
- // Show three HotKeys help information on one ROW.
- //
- gFooterHeight = FOOTER_HEIGHT + (Index / 3);
-
- //
- // Clean the history menu list.
- //
- InitializeListHead (&gMenuList);
//
// Save globals used by SendForm()
@@ -256,65 +360,10 @@ SendForm ( SaveBrowserContext ();
gResetRequired = FALSE;
- Status = EFI_SUCCESS;
- ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
-
- //
- // Seed the dimensions in the global
- //
- gST->ConOut->QueryMode (
- gST->ConOut,
- gST->ConOut->Mode->Mode,
- &gScreenDimensions.RightColumn,
- &gScreenDimensions.BottomRow
- );
-
- if (ScreenDimensions != NULL) {
- //
- // Check local dimension vs. global dimension.
- //
- if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||
- (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)
- ) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- } else {
- //
- // Local dimension validation.
- //
- if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&
- (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&
- ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&
- (
- (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
- SCROLL_ARROW_HEIGHT *
- 2 +
- FRONT_PAGE_HEADER_HEIGHT +
- gFooterHeight +
- 1
- )
- ) {
- CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
- } else {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
- }
-
- gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
- gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);
- gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);
-
- //
- // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
- //
- InitializeBrowserStrings ();
-
- //
- // Ensure we are in Text mode
- //
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gExitRequired = FALSE;
+ Status = EFI_SUCCESS;
+ gEmptyString = L"";
+ gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;
for (Index = 0; Index < HandleCount; Index++) {
Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
@@ -335,7 +384,7 @@ SendForm ( //
// Initialize internal data structures of FormSet
//
- Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE);
+ Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
DestroyFormSet (FormSet);
break;
@@ -343,11 +392,6 @@ SendForm ( Selection->FormSet = FormSet;
//
- // Try to find pre FormSet in the maintain backup list.
- //
- gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);
-
- //
// Display this formset
//
gCurrentSelection = Selection;
@@ -356,27 +400,36 @@ SendForm ( gCurrentSelection = NULL;
- if (EFI_ERROR (Status)) {
- break;
- }
-
- } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
-
- if (gOldFormSet != NULL) {
//
// If no data is changed, don't need to save current FormSet into the maintain list.
//
- if (!IsNvUpdateRequired (gOldFormSet)) {
- CleanBrowserStorage(gOldFormSet);
- RemoveEntryList (&gOldFormSet->Link);
- DestroyFormSet (gOldFormSet);
+ if (!IsNvUpdateRequiredForFormSet (FormSet) && !IsStorageDataChangedForFormSet(FormSet)) {
+ CleanBrowserStorage(FormSet);
+ RemoveEntryList (&FormSet->Link);
+ DestroyFormSet (FormSet);
}
- gOldFormSet = NULL;
- }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
FreePool (Selection);
}
+ //
+ // Still has error info, pop up a message.
+ //
+ if (gBrowserStatus != BROWSER_SUCCESS) {
+ gDisplayFormData.BrowserStatus = gBrowserStatus;
+ gDisplayFormData.ErrorString = gErrorInfo;
+
+ gBrowserStatus = BROWSER_SUCCESS;
+ gErrorInfo = NULL;
+
+ mFormDisplay->FormDisplay (&gDisplayFormData, NULL);
+ }
+
if (ActionRequest != NULL) {
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
if (gResetRequired) {
@@ -384,13 +437,17 @@ SendForm ( }
}
- FreeBrowserStrings ();
- UiFreeMenuList(&gMenuList);
+ mFormDisplay->ExitDisplay();
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->ClearScreen (gST->ConOut);
+ //
+ // Clear the menu history data.
+ //
+ while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+ FreePool (MenuList);
+ }
-Done:
//
// Restore globals used by SendForm()
//
@@ -399,10 +456,93 @@ Done: return Status;
}
+/**
+ Get or set data to the storage.
+
+ @param ResultsDataSize The size of the buffer associatedwith ResultsData.
+ @param ResultsData A string returned from an IFR browser or
+ equivalent. The results string will have no
+ routing information in them.
+ @param RetrieveData A BOOLEAN field which allows an agent to retrieve
+ (if RetrieveData = TRUE) data from the uncommitted
+ browser state information or set (if RetrieveData
+ = FALSE) data in the uncommitted browser state
+ information.
+ @param Storage The pointer to the storage.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+
+**/
+EFI_STATUS
+ProcessStorage (
+ IN OUT UINTN *ResultsDataSize,
+ IN OUT EFI_STRING *ResultsData,
+ IN BOOLEAN RetrieveData,
+ IN BROWSER_STORAGE *Storage
+ )
+{
+ CHAR16 *ConfigResp;
+ EFI_STATUS Status;
+ CHAR16 *StrPtr;
+ UINTN BufferSize;
+ UINTN TmpSize;
+
+ if (RetrieveData) {
+ //
+ // Generate <ConfigResp>
+ //
+ Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.
+ // Also need to consider add "\0" at first time.
+ //
+ StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;
+ BufferSize = StrSize (StrPtr);
+
+
+ //
+ // Copy the data if the input buffer is bigger enough.
+ //
+ if (*ResultsDataSize >= BufferSize) {
+ StrCpy (*ResultsData, StrPtr);
+ }
+
+ *ResultsDataSize = BufferSize;
+ FreePool (ConfigResp);
+ } else {
+ //
+ // Prepare <ConfigResp>
+ //
+ TmpSize = StrLen (*ResultsData);
+ BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);
+ ConfigResp = AllocateZeroPool (BufferSize);
+ ASSERT (ConfigResp != NULL);
+
+ StrCpy (ConfigResp, Storage->ConfigHdr);
+ StrCat (ConfigResp, L"&");
+ StrCat (ConfigResp, *ResultsData);
+
+ //
+ // Update Browser uncommited data
+ //
+ Status = ConfigRespToStorage (Storage, ConfigResp);
+ FreePool (ConfigResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
/**
- This function is called by a callback handler to retrieve uncommitted state
- data from the browser.
+ This routine called this service in the browser to retrieve or set certain uncommitted
+ state information that resides in the open formsets.
@param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
instance.
@@ -440,60 +580,69 @@ BrowserCallback ( {
EFI_STATUS Status;
LIST_ENTRY *Link;
- FORMSET_STORAGE *Storage;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormsetStorage;
FORM_BROWSER_FORMSET *FormSet;
+ UINTN TotalSize;
BOOLEAN Found;
- CHAR16 *ConfigResp;
- CHAR16 *StrPtr;
- UINTN BufferSize;
- UINTN TmpSize;
if (ResultsDataSize == NULL || ResultsData == NULL) {
return EFI_INVALID_PARAMETER;
}
- if (gCurrentSelection == NULL) {
- return EFI_NOT_READY;
- }
-
- Storage = NULL;
- ConfigResp = NULL;
- FormSet = gCurrentSelection->FormSet;
+ TotalSize = *ResultsDataSize;
+ Storage = NULL;
+ Found = FALSE;
+ Status = EFI_SUCCESS;
//
- // Find target storage
+ // If set browser data, pre load all hii formset to avoid set the varstore which is not
+ // saved in browser.
//
- Link = GetFirstNode (&FormSet->StorageListHead);
- if (IsNull (&FormSet->StorageListHead, Link)) {
- return EFI_UNSUPPORTED;
+ if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) {
+ LoadAllHiiFormset();
}
if (VariableGuid != NULL) {
//
- // Try to find target storage
+ // Try to find target storage in the current formset.
//
- Found = FALSE;
- while (!IsNull (&FormSet->StorageListHead, Link)) {
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
- Link = GetNextNode (&FormSet->StorageListHead, Link);
+ Link = GetFirstNode (&gBrowserStorageList);
+ while (!IsNull (&gBrowserStorageList, Link)) {
+ Storage = BROWSER_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserStorageList, Link);
+ //
+ // Check the current storage.
+ //
+ if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
+ continue;
+ }
- if (CompareGuid (&Storage->BrowserStorage->Guid, (EFI_GUID *) VariableGuid)) {
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
- Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
- //
- // Buffer storage require both GUID and Name
- //
- if (VariableName == NULL) {
- return EFI_NOT_FOUND;
- }
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ //
+ // Buffer storage require both GUID and Name
+ //
+ if (VariableName == NULL) {
+ return EFI_NOT_FOUND;
+ }
- if (StrCmp (Storage->BrowserStorage->Name, (CHAR16 *) VariableName) != 0) {
- continue;
- }
+ if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
+ continue;
}
- Found = TRUE;
- break;
}
+
+ Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Different formsets may have same varstore, so here just set the flag
+ // not exit the circle.
+ //
+ Found = TRUE;
+ break;
}
if (!Found) {
@@ -503,65 +652,62 @@ BrowserCallback ( //
// GUID/Name is not specified, take the first storage in FormSet
//
- Storage = FORMSET_STORAGE_FROM_LINK (Link);
- }
-
- if (RetrieveData) {
- //
- // Skip if there is no RequestElement
- //
- if (Storage->ElementCount == 0) {
- return EFI_SUCCESS;
+ if (gCurrentSelection == NULL) {
+ return EFI_NOT_READY;
}
//
// Generate <ConfigResp>
//
- Status = StorageToConfigResp (Storage->BrowserStorage, &ConfigResp, Storage->ConfigRequest);
+ FormSet = gCurrentSelection->FormSet;
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ if (IsNull (&FormSet->StorageListHead, Link)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
if (EFI_ERROR (Status)) {
return Status;
}
+ }
- //
- // Skip <ConfigHdr> and '&' to point to <ConfigBody>
- //
- StrPtr = ConfigResp + StrLen (Storage->BrowserStorage->ConfigHdr) + 1;
+ if (RetrieveData) {
+ Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+ *ResultsDataSize = TotalSize;
+ }
+
+ return Status;
- BufferSize = StrSize (StrPtr);
- if (*ResultsDataSize < BufferSize) {
- *ResultsDataSize = BufferSize;
+}
- FreePool (ConfigResp);
- return EFI_BUFFER_TOO_SMALL;
- }
- *ResultsDataSize = BufferSize;
- CopyMem (ResultsData, StrPtr, BufferSize);
+/**
+ Callback function for SimpleTextInEx protocol install events
- FreePool (ConfigResp);
- } else {
- //
- // Prepare <ConfigResp>
- //
- TmpSize = StrLen (ResultsData);
- BufferSize = (TmpSize + StrLen (Storage->BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
- ConfigResp = AllocateZeroPool (BufferSize);
- ASSERT (ConfigResp != NULL);
+ @param Event the event that is signaled.
+ @param Context not used here.
- StrCpy (ConfigResp, Storage->BrowserStorage->ConfigHdr);
- StrCat (ConfigResp, L"&");
- StrCat (ConfigResp, ResultsData);
+**/
+VOID
+EFIAPI
+FormDisplayCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
- //
- // Update Browser uncommited data
- //
- Status = ConfigRespToStorage (Storage->BrowserStorage, ConfigResp);
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ if (mFormDisplay != NULL) {
+ return;
}
- return EFI_SUCCESS;
+ Status = gBS->LocateProtocol (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ NULL,
+ (VOID **) &mFormDisplay
+ );
}
/**
@@ -582,8 +728,7 @@ InitializeSetup ( )
{
EFI_STATUS Status;
- EFI_INPUT_KEY DefaultHotKey;
- EFI_STRING HelpString;
+ VOID *Registration;
//
// Locate required Hii relative protocols
@@ -596,13 +741,6 @@ InitializeSetup ( ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
- &gEfiHiiStringProtocolGuid,
- NULL,
- (VOID **) &mHiiString
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->LocateProtocol (
&gEfiHiiConfigRoutingProtocolGuid,
NULL,
(VOID **) &mHiiConfigRouting
@@ -616,30 +754,6 @@ InitializeSetup ( );
//
- // Publish our HII data
- //
- gHiiHandle = HiiAddPackages (
- &gSetupBrowserGuid,
- ImageHandle,
- SetupBrowserStrings,
- NULL
- );
- ASSERT (gHiiHandle != NULL);
-
- //
- // Initialize Driver private data
- //
- gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
- ASSERT (gBannerData != NULL);
-
- //
- // Initialize generic help strings.
- //
- gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
- gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle);
- gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle);
-
- //
// Install FormBrowser2 protocol
//
mPrivateData.Handle = NULL;
@@ -652,34 +766,45 @@ InitializeSetup ( ASSERT_EFI_ERROR (Status);
//
- // Install default HotKey F10 for Save
- //
- DefaultHotKey.UnicodeChar = CHAR_NULL;
- HelpString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);
- DefaultHotKey.ScanCode = SCAN_F10;
- RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString);
- FreePool (HelpString);
- //
- // Install default HotKey F9 for Reset To Defaults
- //
- DefaultHotKey.ScanCode = SCAN_F9;
- HelpString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);
- RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString);
- FreePool (HelpString);
-
- //
- // Install FormBrowserEx protocol
+ // Install FormBrowserEx2 protocol
//
+ InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
mPrivateData.Handle = NULL;
Status = gBS->InstallProtocolInterface (
&mPrivateData.Handle,
+ &gEdkiiFormBrowserEx2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FormBrowserEx2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
&gEfiFormBrowserExProtocolGuid,
EFI_NATIVE_INTERFACE,
&mPrivateData.FormBrowserEx
);
ASSERT_EFI_ERROR (Status);
- return Status;
+ InitializeDisplayFormData ();
+
+ Status = gBS->LocateProtocol (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ NULL,
+ (VOID **) &mFormDisplay
+ );
+
+ if (EFI_ERROR (Status)) {
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ TPL_CALLBACK,
+ FormDisplayCallback,
+ NULL,
+ &Registration
+ );
+ }
+
+ return EFI_SUCCESS;
}
@@ -815,58 +940,6 @@ NewStringCat ( *Dest = NewString;
}
-
-/**
- Synchronize or restore Storage's Edit copy and Shadow copy.
-
- @param Storage The Storage to be synchronized.
- @param SyncOrRestore Sync the buffer to editbuffer or Restore the
- editbuffer to buffer
- if TRUE, copy the editbuffer to the buffer.
- if FALSE, copy the buffer to the editbuffer.
-
-**/
-VOID
-SynchronizeStorage (
- IN BROWSER_STORAGE *Storage,
- IN BOOLEAN SyncOrRestore
- )
-{
- LIST_ENTRY *Link;
- NAME_VALUE_NODE *Node;
-
- switch (Storage->Type) {
- case EFI_HII_VARSTORE_BUFFER:
- case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
- if (SyncOrRestore) {
- CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);
- } else {
- CopyMem (Storage->EditBuffer, Storage->Buffer, Storage->Size);
- }
- break;
-
- case EFI_HII_VARSTORE_NAME_VALUE:
- Link = GetFirstNode (&Storage->NameValueListHead);
- while (!IsNull (&Storage->NameValueListHead, Link)) {
- Node = NAME_VALUE_NODE_FROM_LINK (Link);
-
- if (SyncOrRestore) {
- NewStringCpy (&Node->Value, Node->EditValue);
- } else {
- NewStringCpy (&Node->EditValue, Node->Value);
- }
-
- Link = GetNextNode (&Storage->NameValueListHead, Link);
- }
- break;
-
- case EFI_HII_VARSTORE_EFI_VARIABLE:
- default:
- break;
- }
-}
-
-
/**
Get Value for given Name from a NameValue Storage.
@@ -923,6 +996,7 @@ GetValueByName ( @param Name The Name.
@param Value The Value to set.
@param SetValueTo Whether update editValue or Value.
+ @param ReturnNode The node use the input name.
@retval EFI_SUCCESS Value found for given Name.
@retval EFI_NOT_FOUND No such Name found in NameValue storage.
@@ -930,10 +1004,11 @@ GetValueByName ( **/
EFI_STATUS
SetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN CHAR16 *Value,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN CHAR16 *Value,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
+ OUT NAME_VALUE_NODE **ReturnNode
)
{
LIST_ENTRY *Link;
@@ -964,6 +1039,11 @@ SetValueByName ( } else {
Node->Value = Buffer;
}
+
+ if (ReturnNode != NULL) {
+ *ReturnNode = Node;
+ }
+
return EFI_SUCCESS;
}
@@ -980,6 +1060,7 @@ SetValueByName ( @param Storage The Storage to be conveted.
@param ConfigResp The returned <ConfigResp>.
@param ConfigRequest The ConfigRequest string.
+ @param GetEditBuf Get the data from editbuffer or buffer.
@retval EFI_SUCCESS Convert success.
@retval EFI_INVALID_PARAMETER Incorrect storage type.
@@ -989,23 +1070,26 @@ EFI_STATUS StorageToConfigResp (
IN BROWSER_STORAGE *Storage,
IN CHAR16 **ConfigResp,
- IN CHAR16 *ConfigRequest
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN GetEditBuf
)
{
EFI_STATUS Status;
EFI_STRING Progress;
LIST_ENTRY *Link;
NAME_VALUE_NODE *Node;
+ UINT8 *SourceBuf;
Status = EFI_SUCCESS;
switch (Storage->Type) {
case EFI_HII_VARSTORE_BUFFER:
case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
Status = mHiiConfigRouting->BlockToConfig (
mHiiConfigRouting,
ConfigRequest,
- Storage->EditBuffer,
+ SourceBuf,
Storage->Size,
ConfigResp,
&Progress
@@ -1024,7 +1108,11 @@ StorageToConfigResp ( NewStringCat (ConfigResp, L"&");
NewStringCat (ConfigResp, Node->Name);
NewStringCat (ConfigResp, L"=");
- NewStringCat (ConfigResp, Node->EditValue);
+ if (GetEditBuf) {
+ NewStringCat (ConfigResp, Node->EditValue);
+ } else {
+ NewStringCat (ConfigResp, Node->Value);
+ }
}
Link = GetNextNode (&Storage->NameValueListHead, Link);
}
@@ -1105,7 +1193,7 @@ ConfigRespToStorage ( if (StrPtr != NULL) {
*StrPtr = 0;
}
- SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer);
+ SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
}
break;
@@ -1531,7 +1619,7 @@ GetQuestionValue ( if (IsBufferStorage) {
CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
} else {
- SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer);
+ SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
}
if (Result != NULL) {
@@ -1581,8 +1669,10 @@ SetQuestionValue ( CHAR16 *TemName;
CHAR16 *TemString;
UINTN Index;
+ NAME_VALUE_NODE *Node;
Status = EFI_SUCCESS;
+ Node = NULL;
if (SetValueTo >= GetSetValueWithMax) {
return EFI_INVALID_PARAMETER;
@@ -1717,6 +1807,14 @@ SetQuestionValue ( //
CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
}
+ //
+ // Check whether question value has been changed.
+ //
+ if (CompareMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth) != 0) {
+ Question->ValueChanged = TRUE;
+ } else {
+ Question->ValueChanged = FALSE;
+ }
} else {
if (IsString) {
//
@@ -1748,8 +1846,19 @@ SetQuestionValue ( }
}
- Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo);
+ Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
FreePool (Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check whether question value has been changed.
+ //
+ if (StrCmp (Node->Value, Node->EditValue) != 0) {
+ Question->ValueChanged = TRUE;
+ } else {
+ Question->ValueChanged = FALSE;
+ }
}
} else if (SetValueTo == GetSetValueWithHiiDriver) {
if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
@@ -1868,12 +1977,12 @@ SetQuestionValue ( /**
- Perform inconsistent check for a Form.
+ Perform nosubmitif check for a Form.
@param FormSet FormSet data structure.
@param Form Form data structure.
@param Question The Question to be validated.
- @param Type Validation type: InConsistent or NoSubmit
+ @param Type Validation type: NoSubmit
@retval EFI_SUCCESS Form validation pass.
@retval other Form validation failed.
@@ -1891,12 +2000,9 @@ ValidateQuestion ( LIST_ENTRY *Link;
LIST_ENTRY *ListHead;
EFI_STRING PopUp;
- EFI_INPUT_KEY Key;
FORM_EXPRESSION *Expression;
- if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
- ListHead = &Question->InconsistentListHead;
- } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
+ if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
ListHead = &Question->NoSubmitListHead;
} else {
return EFI_UNSUPPORTED;
@@ -1920,10 +2026,10 @@ ValidateQuestion ( //
if (Expression->Error != 0) {
PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
- do {
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
- FreePool (PopUp);
+ if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
+ gBrowserStatus = BROWSER_NO_SUBMIT_IF;
+ gErrorInfo = PopUp;
+ }
}
return EFI_NOT_READY;
@@ -1987,7 +2093,8 @@ NoSubmitCheck ( Fill storage's edit copy with settings requested from Configuration Driver.
@param FormSet FormSet data structure.
- @param ConfigInfo The config info related to this form.
+ @param Storage The storage which need to sync.
+ @param ConfigRequest The config request string which used to sync storage.
@param SyncOrRestore Sync the buffer to editbuffer or Restore the
editbuffer to buffer
if TRUE, copy the editbuffer to the buffer.
@@ -1997,10 +2104,11 @@ NoSubmitCheck ( **/
EFI_STATUS
-SynchronizeStorageForForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,
- IN BOOLEAN SyncOrRestore
+SynchronizeStorage (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT BROWSER_STORAGE *Storage,
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN SyncOrRestore
)
{
EFI_STATUS Status;
@@ -2014,57 +2122,52 @@ SynchronizeStorageForForm ( Status = EFI_SUCCESS;
Result = NULL;
- if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
- return EFI_NOT_FOUND;
- }
- if (ConfigInfo->ElementCount == 0) {
- //
- // Skip if there is no RequestElement
- //
- return EFI_SUCCESS;
- }
-
- if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
- (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
- BufferSize = ConfigInfo->Storage->Size;
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ BufferSize = Storage->Size;
if (SyncOrRestore) {
- Src = ConfigInfo->Storage->EditBuffer;
- Dst = ConfigInfo->Storage->Buffer;
+ Src = Storage->EditBuffer;
+ Dst = Storage->Buffer;
} else {
- Src = ConfigInfo->Storage->Buffer;
- Dst = ConfigInfo->Storage->EditBuffer;
+ Src = Storage->Buffer;
+ Dst = Storage->EditBuffer;
}
- Status = mHiiConfigRouting->BlockToConfig(
- mHiiConfigRouting,
- ConfigInfo->ConfigRequest,
- Src,
- BufferSize,
- &Result,
- &Progress
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ if (ConfigRequest != NULL) {
+ Status = mHiiConfigRouting->BlockToConfig(
+ mHiiConfigRouting,
+ ConfigRequest,
+ Src,
+ BufferSize,
+ &Result,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
- Status = mHiiConfigRouting->ConfigToBlock (
- mHiiConfigRouting,
- Result,
- Dst,
- &BufferSize,
- &Progress
- );
- if (Result != NULL) {
- FreePool (Result);
+ Status = mHiiConfigRouting->ConfigToBlock (
+ mHiiConfigRouting,
+ Result,
+ Dst,
+ &BufferSize,
+ &Progress
+ );
+ if (Result != NULL) {
+ FreePool (Result);
+ }
+ } else {
+ CopyMem (Dst, Src, BufferSize);
}
- } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
- Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);
- while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
Node = NAME_VALUE_NODE_FROM_LINK (Link);
- if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {
+ if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
+ (ConfigRequest == NULL)) {
if (SyncOrRestore) {
NewStringCpy (&Node->Value, Node->EditValue);
} else {
@@ -2072,7 +2175,7 @@ SynchronizeStorageForForm ( }
}
- Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
}
}
@@ -2095,20 +2198,9 @@ SendDiscardInfoToDriver ( {
LIST_ENTRY *Link;
FORM_BROWSER_STATEMENT *Question;
- EFI_STATUS Status;
- EFI_HII_VALUE HiiValue;
- UINT8 *BufferValue;
- BOOLEAN ValueChanged;
EFI_IFR_TYPE_VALUE *TypeValue;
EFI_BROWSER_ACTION_REQUEST ActionRequest;
- ValueChanged = FALSE;
- BufferValue = NULL;
-
- if(!Form->NvUpdateRequired) {
- return;
- }
-
Link = GetFirstNode (&Form->StatementListHead);
while (!IsNull (&Form->StatementListHead, Link)) {
Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
@@ -2122,45 +2214,10 @@ SendDiscardInfoToDriver ( continue;
}
- if (Question->BufferValue != NULL) {
- BufferValue = AllocateZeroPool (Question->StorageWidth);
- ASSERT (BufferValue != NULL);
- CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth);
- } else {
- HiiValue.Type = Question->HiiValue.Type;
- CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE));
- }
-
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
- if (EFI_ERROR (Status)) {
- if (BufferValue != NULL) {
- FreePool (BufferValue);
- BufferValue = NULL;
- }
+ if (!Question->ValueChanged) {
continue;
}
- if (Question->BufferValue != NULL) {
- if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) {
- ValueChanged = TRUE;
- }
- } else {
- if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) {
- ValueChanged = TRUE;
- }
- }
-
- if (BufferValue != NULL) {
- FreePool (BufferValue);
- BufferValue = NULL;
- }
-
- if (!ValueChanged) {
- continue;
- }
-
- ValueChanged = FALSE;
-
if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
} else {
@@ -2225,6 +2282,78 @@ ValidateFormSet ( return Find;
}
+/**
+ Check whether need to enable the reset flag in form level.
+ Also clean all ValueChanged flag in question.
+
+ @param SetFlag Whether need to set the Reset Flag.
+ @param Form Form data structure.
+
+**/
+VOID
+UpdateFlagForForm (
+ IN BOOLEAN SetFlag,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ BOOLEAN FindOne;
+
+ FindOne = FALSE;
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {
+ gResetRequired = TRUE;
+ }
+
+ if (Question->ValueChanged) {
+ Question->ValueChanged = FALSE;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+}
+
+/**
+ Check whether need to enable the reset flag.
+ Also clean ValueChanged flag for all statements.
+
+ Form level or formset level, only one.
+
+ @param SetFlag Whether need to set the Reset Flag.
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+ValueChangeResetFlagUpdate (
+ IN BOOLEAN SetFlag,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_FORM *CurrentForm;
+ LIST_ENTRY *Link;
+
+ //
+ // Form != NULL means only check form level.
+ //
+ if (Form != NULL) {
+ UpdateFlagForForm(SetFlag, Form);
+ return;
+ }
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ UpdateFlagForForm(SetFlag, CurrentForm);
+ }
+}
/**
Discard data based on the input setting scope (Form, FormSet or System).
@@ -2256,7 +2385,7 @@ DiscardForm ( return EFI_UNSUPPORTED;
}
- if (SettingScope == FormLevel && Form->NvUpdateRequired) {
+ if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
ConfigInfo = NULL;
Link = GetFirstNode (&Form->ConfigRequestHead);
while (!IsNull (&Form->ConfigRequestHead, Link)) {
@@ -2277,7 +2406,7 @@ DiscardForm ( //
// Prepare <ConfigResp>
//
- SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);
+ SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
//
// Call callback with Changed type to inform the driver.
@@ -2285,8 +2414,8 @@ DiscardForm ( SendDiscardInfoToDriver (FormSet, Form);
}
- Form->NvUpdateRequired = FALSE;
- } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
+ ValueChangeResetFlagUpdate (FALSE, NULL, Form);
+ } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
//
// Discard Buffer storage or Name/Value storage
@@ -2307,7 +2436,7 @@ DiscardForm ( continue;
}
- SynchronizeStorage(Storage->BrowserStorage, FALSE);
+ SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
}
Link = GetFirstNode (&FormSet->FormListHead);
@@ -2321,7 +2450,7 @@ DiscardForm ( SendDiscardInfoToDriver (FormSet, Form);
}
- UpdateNvInfoInForm (FormSet, FALSE);
+ ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
} else if (SettingScope == SystemLevel) {
//
// System Level Discard.
@@ -2401,7 +2530,7 @@ SubmitForm ( return Status;
}
- if (SettingScope == FormLevel && Form->NvUpdateRequired) {
+ if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
ConfigInfo = NULL;
Link = GetFirstNode (&Form->ConfigRequestHead);
while (!IsNull (&Form->ConfigRequestHead, Link)) {
@@ -2423,7 +2552,7 @@ SubmitForm ( //
// 1. Prepare <ConfigResp>
//
- Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest);
+ Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -2499,14 +2628,14 @@ SubmitForm ( //
// 3. Config success, update storage shadow Buffer, only update the data belong to this form.
//
- SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);
+ SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
}
//
// 4. Update the NV flag.
//
- Form->NvUpdateRequired = FALSE;
- } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
+ ValueChangeResetFlagUpdate(TRUE, NULL, Form);
+ } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
//
// Submit Buffer storage or Name/Value storage
//
@@ -2530,7 +2659,7 @@ SubmitForm ( //
// 1. Prepare <ConfigResp>
//
- Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest);
+ Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -2602,13 +2731,13 @@ SubmitForm ( //
// 3. Config success, update storage shadow Buffer
//
- SynchronizeStorage (Storage, TRUE);
+ SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE);
}
//
// 4. Update the NV flag.
//
- UpdateNvInfoInForm (FormSet, FALSE);
+ ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
} else if (SettingScope == SystemLevel) {
//
// System Level Save.
@@ -2864,6 +2993,138 @@ GetDefaultIdForCallBack ( }
}
+
+
+/**
+ 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;
+ }
+}
+
+/**
+ 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.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ INTN Result;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+ //
+ // Check the suppressif condition, only a valid option can be return.
+ //
+ if ((Option->SuppressExpression == NULL) ||
+ ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
+ return Option;
+ }
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return NULL;
+}
+
+
/**
Reset Question to its default value.
@@ -3155,11 +3416,7 @@ ExtractDefault ( LIST_ENTRY *FormLink;
LIST_ENTRY *Link;
FORM_BROWSER_STATEMENT *Question;
- FORM_BROWSER_FORMSET *BackUpFormSet;
FORM_BROWSER_FORMSET *LocalFormSet;
- EFI_HII_HANDLE *HiiHandles;
- UINTN Index;
- EFI_GUID ZeroGuid;
Status = EFI_SUCCESS;
@@ -3229,10 +3486,6 @@ ExtractDefault ( if ((Question->Storage != NULL) &&
(Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
- //
- // Update Form NV flag.
- //
- Form->NvUpdateRequired = TRUE;
}
}
} else if (SettingScope == FormSetLevel) {
@@ -3244,65 +3497,9 @@ ExtractDefault ( }
} else if (SettingScope == SystemLevel) {
//
- // Open all FormSet by locate HII packages.
- // Initiliaze the maintain FormSet to store default data as back up data.
+ // Preload all Hii formset.
//
- BackUpFormSet = gOldFormSet;
- gOldFormSet = NULL;
-
- //
- // Get all the Hii handles
- //
- HiiHandles = HiiGetHiiHandles (NULL);
- ASSERT (HiiHandles != NULL);
-
- //
- // Search for formset of each class type
- //
- for (Index = 0; HiiHandles[Index] != NULL; Index++) {
- //
- // Check HiiHandles[Index] does exist in global maintain list.
- //
- if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
- continue;
- }
-
- //
- // Initilize FormSet Setting
- //
- LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
- ASSERT (LocalFormSet != NULL);
- ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
- Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);
- if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
- DestroyFormSet (LocalFormSet);
- continue;
- }
- Status = InitializeCurrentSetting (LocalFormSet);
- if (EFI_ERROR (Status)) {
- DestroyFormSet (LocalFormSet);
- continue;
- }
- //
- // Initilize Questions' Value
- //
- Status = LoadFormSetConfig (NULL, LocalFormSet);
- if (EFI_ERROR (Status)) {
- DestroyFormSet (LocalFormSet);
- continue;
- }
-
- //
- // Add FormSet into the maintain list.
- //
- InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);
- }
-
- //
- // Free resources, and restore gOldFormSet and gClassOfVfr
- //
- FreePool (HiiHandles);
- gOldFormSet = BackUpFormSet;
+ LoadAllHiiFormset();
//
// Set Default Value for each FormSet in the maintain list.
@@ -3321,6 +3518,81 @@ ExtractDefault ( return EFI_SUCCESS;
}
+
+/**
+ Validate whether this question's value has changed.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval TRUE Question's value has changed.
+ @retval FALSE Question's value has not changed
+
+**/
+BOOLEAN
+IsQuestionValueChanged (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ )
+{
+ EFI_HII_VALUE BackUpValue;
+ CHAR8 *BackUpBuffer;
+ EFI_STATUS Status;
+ BOOLEAN ValueChanged;
+ UINTN BufferWidth;
+
+ //
+ // For quetion without storage, always mark it as data not changed.
+ //
+ if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
+ return FALSE;
+ }
+
+ BackUpBuffer = NULL;
+ ValueChanged = FALSE;
+
+ switch (Question->Operand) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ BufferWidth = Question->StorageWidth;
+ BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ break;
+
+ case EFI_IFR_STRING_OP:
+ case EFI_IFR_PASSWORD_OP:
+ BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
+ BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ break;
+
+ default:
+ BufferWidth = 0;
+ break;
+ }
+ CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
+
+ Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
+ ASSERT_EFI_ERROR(Status);
+
+ if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
+ CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
+ ValueChanged = TRUE;
+ }
+
+ CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
+ CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
+
+ if (BackUpBuffer != NULL) {
+ FreePool (BackUpBuffer);
+ }
+
+ return ValueChanged;
+}
+
/**
Initialize Question's Edit copy from Storage.
@@ -3354,7 +3626,11 @@ LoadFormConfig ( //
// Initialize local copy of Value for each Question
//
- Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+ if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
+ } else {
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+ }
if (EFI_ERROR (Status)) {
return Status;
}
@@ -3394,6 +3670,11 @@ LoadFormConfig ( Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
}
+ //
+ // Update Question Value changed flag.
+ //
+ Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);
+
Link = GetNextNode (&Form->StatementListHead, Link);
}
@@ -3437,6 +3718,11 @@ LoadFormSetConfig ( Link = GetNextNode (&FormSet->FormListHead, Link);
}
+ //
+ // Finished question initialization.
+ //
+ FormSet->QuestionInited = TRUE;
+
return EFI_SUCCESS;
}
@@ -3491,6 +3777,13 @@ RemoveConfigRequest ( CHAR16 *NextRequestElement;
CHAR16 *SearchKey;
+ //
+ // No request element in it, just return.
+ //
+ if (ConfigRequest == NULL) {
+ return;
+ }
+
if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
//
// "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
@@ -3565,6 +3858,7 @@ CleanBrowserStorage ( {
LIST_ENTRY *Link;
FORMSET_STORAGE *Storage;
+ CHAR16 *ConfigRequest;
Link = GetFirstNode (&FormSet->StorageListHead);
while (!IsNull (&FormSet->StorageListHead, Link)) {
@@ -3572,7 +3866,8 @@ CleanBrowserStorage ( Link = GetNextNode (&FormSet->StorageListHead, Link);
if ((Storage->BrowserStorage->Type != EFI_HII_VARSTORE_BUFFER) &&
- (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE)) {
+ (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) &&
+ (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
continue;
}
@@ -3580,7 +3875,8 @@ CleanBrowserStorage ( continue;
}
- RemoveConfigRequest (Storage->BrowserStorage, Storage->ConfigRequest);
+ ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;
+ RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);
}
}
@@ -3651,7 +3947,6 @@ AppendConfigRequest ( Adjust the config request info, remove the request elements which already in AllConfigRequest string.
@param Storage Form set Storage.
- @param ConfigRequest Return the ConfigRequest info.
@retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
@retval FALSE All elements covered by current used elements.
@@ -3659,8 +3954,7 @@ AppendConfigRequest ( **/
BOOLEAN
ConfigRequestAdjust (
- IN FORMSET_STORAGE *Storage,
- OUT CHAR16 **ConfigRequest
+ IN FORMSET_STORAGE *Storage
)
{
CHAR16 *RequestElement;
@@ -3676,7 +3970,10 @@ ConfigRequestAdjust ( if (Storage->BrowserStorage->ConfigRequest == NULL) {
Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
- *ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
+ if (Storage->ConfigElements != NULL) {
+ FreePool (Storage->ConfigElements);
+ }
+ Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
return TRUE;
}
@@ -3745,7 +4042,10 @@ ConfigRequestAdjust ( }
if (RetVal) {
- *ConfigRequest = RetBuf;
+ if (Storage->ConfigElements != NULL) {
+ FreePool (Storage->ConfigElements);
+ }
+ Storage->ConfigElements = RetBuf;
} else {
FreePool (RetBuf);
}
@@ -3754,15 +4054,162 @@ ConfigRequestAdjust ( }
/**
+
+ Base on ConfigRequest info to get default value for current formset.
+
+ ConfigRequest info include the info about which questions in current formset need to
+ get default value. This function only get these questions default value.
+
+ @param FormSet FormSet data structure.
+ @param Storage Storage need to update value.
+ @param ConfigRequest The config request string.
+
+**/
+VOID
+GetDefaultForFormset (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *ConfigRequest
+ )
+{
+ UINT8 *BackUpBuf;
+ UINTN BufferSize;
+ LIST_ENTRY BackUpList;
+ NAME_VALUE_NODE *Node;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NodeLink;
+ NAME_VALUE_NODE *TmpNode;
+ EFI_STATUS Status;
+ EFI_STRING Progress;
+ EFI_STRING Result;
+
+ BackUpBuf = NULL;
+ InitializeListHead(&BackUpList);
+
+ //
+ // Back update the edit buffer.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);
+ ASSERT (BackUpBuf != NULL);
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+
+ //
+ // Only back Node belong to this formset.
+ //
+ if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {
+ continue;
+ }
+
+ TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);
+ TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);
+ TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
+
+ InsertTailList(&BackUpList, &TmpNode->Link);
+ }
+ }
+
+ //
+ // Get default value.
+ //
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
+
+ //
+ // Update the question value based on the input ConfigRequest.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ ASSERT (BackUpBuf != NULL);
+ BufferSize = Storage->Size;
+ Status = mHiiConfigRouting->BlockToConfig(
+ mHiiConfigRouting,
+ ConfigRequest,
+ Storage->EditBuffer,
+ BufferSize,
+ &Result,
+ &Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = mHiiConfigRouting->ConfigToBlock (
+ mHiiConfigRouting,
+ Result,
+ BackUpBuf,
+ &BufferSize,
+ &Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (Result != NULL) {
+ FreePool (Result);
+ }
+
+ CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);
+ FreePool (BackUpBuf);
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Update question value, only element in ConfigReqeust will be update.
+ //
+ Link = GetFirstNode (&BackUpList);
+ while (!IsNull (&BackUpList, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+ Link = GetNextNode (&BackUpList, Link);
+
+ if (StrStr (ConfigRequest, Node->Name) != NULL) {
+ continue;
+ }
+
+ NodeLink = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, NodeLink)) {
+ TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);
+ NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);
+
+ if (StrCmp (Node->Name, TmpNode->Name) != 0) {
+ continue;
+ }
+
+ FreePool (TmpNode->EditValue);
+ TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
+
+ RemoveEntryList (&Node->Link);
+ FreePool (Node->EditValue);
+ FreePool (Node->Name);
+ FreePool (Node);
+ }
+ }
+
+ //
+ // Restore the Name/Value node.
+ //
+ Link = GetFirstNode (&BackUpList);
+ while (!IsNull (&BackUpList, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+ Link = GetNextNode (&BackUpList, Link);
+
+ //
+ // Free this node.
+ //
+ RemoveEntryList (&Node->Link);
+ FreePool (Node->EditValue);
+ FreePool (Node->Name);
+ FreePool (Node);
+ }
+ }
+}
+
+/**
Fill storage's edit copy with settings requested from Configuration Driver.
@param FormSet FormSet data structure.
@param Storage Buffer Storage.
- @retval EFI_SUCCESS The function completed successfully.
-
**/
-EFI_STATUS
+VOID
LoadStorage (
IN FORM_BROWSER_FORMSET *FormSet,
IN FORMSET_STORAGE *Storage
@@ -3772,18 +4219,17 @@ LoadStorage ( EFI_STRING Progress;
EFI_STRING Result;
CHAR16 *StrPtr;
- CHAR16 *ConfigRequest;
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
- return EFI_SUCCESS;
- }
+ switch (Storage->BrowserStorage->Type) {
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ return;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ if (Storage->BrowserStorage->ReferenceCount > 1) {
+ ConfigRequestAdjust(Storage);
+ return;
+ }
- if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
- Status = EFI_SUCCESS;
- //
- // EFI varstore data all get from variable, so no need to get again.
- //
- if (Storage->BrowserStorage->ReferenceCount == 1) {
Status = gRT->GetVariable (
Storage->BrowserStorage->Name,
&Storage->BrowserStorage->Guid,
@@ -3791,55 +4237,78 @@ LoadStorage ( (UINTN*)&Storage->BrowserStorage->Size,
Storage->BrowserStorage->EditBuffer
);
- }
- return Status;
- }
+ //
+ // If get variable fail, extract default from IFR binary
+ //
+ if (EFI_ERROR (Status)) {
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
+ }
- if (FormSet->ConfigAccess == NULL) {
- return EFI_NOT_FOUND;
- }
+ Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
+ //
+ // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
+ //
+ SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);
+ break;
- if (Storage->ElementCount == 0) {
- //
- // Skip if there is no RequestElement
- //
- return EFI_SUCCESS;
- }
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ //
+ // Skip if there is no RequestElement
+ //
+ if (Storage->ElementCount == 0) {
+ return;
+ }
- //
- // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig
- // will used to call ExtractConfig.
- //
- if (!ConfigRequestAdjust(Storage, &ConfigRequest)) {
- return EFI_SUCCESS;
- }
+ //
+ // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig
+ // will used to call ExtractConfig.
+ // If not elements need to udpate, return.
+ //
+ if (!ConfigRequestAdjust(Storage)) {
+ return;
+ }
+ ASSERT (Storage->ConfigElements != NULL);
- //
- // Request current settings from Configuration Driver
- //
- Status = FormSet->ConfigAccess->ExtractConfig (
- FormSet->ConfigAccess,
- ConfigRequest,
- &Progress,
- &Result
- );
- FreePool (ConfigRequest);
+ Status = EFI_NOT_FOUND;
+ if (FormSet->ConfigAccess != NULL) {
+ //
+ // Request current settings from Configuration Driver
+ //
+ Status = FormSet->ConfigAccess->ExtractConfig (
+ FormSet->ConfigAccess,
+ Storage->ConfigElements,
+ &Progress,
+ &Result
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Convert Result from <ConfigAltResp> to <ConfigResp>
+ //
+ StrPtr = StrStr (Result, L"&GUID=");
+ if (StrPtr != NULL) {
+ *StrPtr = L'\0';
+ }
+
+ Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
+ FreePool (Result);
+ }
+ }
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ if (EFI_ERROR (Status)) {
+ //
+ // Base on the configRequest string to get default value.
+ //
+ GetDefaultForFormset (FormSet, Storage->BrowserStorage, Storage->ConfigElements);
+ }
- //
- // Convert Result from <ConfigAltResp> to <ConfigResp>
- //
- StrPtr = StrStr (Result, L"&GUID=");
- if (StrPtr != NULL) {
- *StrPtr = L'\0';
- }
+ SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigElements, TRUE);
+ break;
- Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
- FreePool (Result);
- return Status;
+ default:
+ break;
+ }
}
/**
@@ -3847,22 +4316,15 @@ LoadStorage ( @param FormSet FormSet data structure.
- @retval EFI_SUCCESS The function completed successfully.
-
**/
-EFI_STATUS
+VOID
InitializeCurrentSetting (
IN OUT FORM_BROWSER_FORMSET *FormSet
)
{
LIST_ENTRY *Link;
- LIST_ENTRY *Link2;
FORMSET_STORAGE *Storage;
- FORMSET_STORAGE *StorageSrc;
- FORMSET_STORAGE *OldStorage;
- FORM_BROWSER_FORM *Form;
- FORM_BROWSER_FORM *Form2;
- EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *OldFormSet;
//
// Extract default from IFR binary for no storage questions.
@@ -3876,77 +4338,21 @@ InitializeCurrentSetting ( while (!IsNull (&FormSet->StorageListHead, Link)) {
Storage = FORMSET_STORAGE_FROM_LINK (Link);
- OldStorage = NULL;
- if (gOldFormSet != NULL) {
- //
- // Try to find the Storage in backup formset gOldFormSet
- //
- Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
- while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
- StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
-
- if (StorageSrc->VarStoreId == Storage->VarStoreId) {
- OldStorage = StorageSrc;
- break;
- }
-
- Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
- }
- }
-
- //
- // Storage is not found in backup formset and current global storage not has other driver used,
- // request it from ConfigDriver
- //
- if (OldStorage == NULL) {
- Status = LoadStorage (FormSet, Storage);
-
- if (EFI_ERROR (Status)) {
- //
- // If get last time changed value failed, extract default from IFR binary
- //
- ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
- //
- // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag
- // in current situation.
- //
- UpdateNvInfoInForm (FormSet, FALSE);
- }
-
- //
- // Now Edit Buffer is filled with default values(lower priority) or current
- // settings(higher priority), sychronize it to shadow Buffer
- //
- SynchronizeStorage (Storage->BrowserStorage, TRUE);
- }
+ LoadStorage (FormSet, Storage);
Link = GetNextNode (&FormSet->StorageListHead, Link);
}
//
- // If has old formset, get the old nv update status.
+ // Try to find pre FormSet in the maintain backup list.
+ // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
//
- if (gOldFormSet != NULL) {
- Link = GetFirstNode (&FormSet->FormListHead);
- while (!IsNull (&FormSet->FormListHead, Link)) {
- Form = FORM_BROWSER_FORM_FROM_LINK (Link);
-
- Link2 = GetFirstNode (&gOldFormSet->FormListHead);
- while (!IsNull (&gOldFormSet->FormListHead, Link2)) {
- Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);
-
- if (Form->FormId == Form2->FormId) {
- Form->NvUpdateRequired = Form2->NvUpdateRequired;
- break;
- }
-
- Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);
- }
- Link = GetNextNode (&FormSet->FormListHead, Link);
- }
+ OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
+ if (OldFormSet != NULL) {
+ RemoveEntryList (&OldFormSet->Link);
+ DestroyFormSet (OldFormSet);
}
-
- return EFI_SUCCESS;
+ InsertTailList (&gBrowserFormSetList, &FormSet->Link);
}
@@ -4129,7 +4535,6 @@ GetIfrBinaryData ( found in package list.
On output, GUID of the formset found(if not NULL).
@param FormSet FormSet data structure.
- @param UpdateGlobalVar Whether need to update the global variable.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND The specified FormSet could not be found.
@@ -4139,13 +4544,11 @@ EFI_STATUS InitializeFormSet (
IN EFI_HII_HANDLE Handle,
IN OUT EFI_GUID *FormSetGuid,
- OUT FORM_BROWSER_FORMSET *FormSet,
- IN BOOLEAN UpdateGlobalVar
+ OUT FORM_BROWSER_FORMSET *FormSet
)
{
EFI_STATUS Status;
EFI_HANDLE DriverHandle;
- UINT16 Index;
Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
if (EFI_ERROR (Status)) {
@@ -4155,6 +4558,7 @@ InitializeFormSet ( FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
FormSet->HiiHandle = Handle;
CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
+ FormSet->QuestionInited = FALSE;
//
// Retrieve ConfigAccess Protocol associated with this HiiPackageList
@@ -4181,55 +4585,8 @@ InitializeFormSet ( // Parse the IFR binary OpCodes
//
Status = ParseOpCodes (FormSet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // If not need to update the global variable, just return.
- //
- if (!UpdateGlobalVar) {
- return Status;
- }
-
- //
- // Set VFR type by FormSet SubClass field
- //
- gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
- if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
- gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
- }
-
- //
- // Set VFR type by FormSet class guid
- //
- for (Index = 0; Index < 3; Index ++) {
- if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
- gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
- break;
- }
- }
-
- gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING;
-
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
- gFrontPageHandle = FormSet->HiiHandle;
- gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;
- }
-
- //
- // Match GUID to find out the function key setting. If match fail, use the default setting.
- //
- for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
- if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
- //
- // Update the function key setting.
- //
- gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
- }
- }
-
- return EFI_SUCCESS;
+ return Status;
}
@@ -4245,6 +4602,7 @@ SaveBrowserContext ( )
{
BROWSER_CONTEXT *Context;
+ FORM_ENTRY_INFO *MenuList;
gBrowserContextCount++;
if (gBrowserContextCount == 1) {
@@ -4254,6 +4612,11 @@ SaveBrowserContext ( return;
}
+ //
+ // Not support SendForm nest in another SendForm, assert here.
+ //
+ ASSERT (FALSE);
+
Context = AllocatePool (sizeof (BROWSER_CONTEXT));
ASSERT (Context != NULL);
@@ -4262,47 +4625,20 @@ SaveBrowserContext ( //
// Save FormBrowser context
//
- Context->BannerData = gBannerData;
- Context->ClassOfVfr = gClassOfVfr;
- Context->FunctionKeySetting = gFunctionKeySetting;
Context->ResetRequired = gResetRequired;
- Context->Direction = gDirection;
- Context->EnterString = gEnterString;
- Context->EnterCommitString = gEnterCommitString;
- Context->EnterEscapeString = gEnterEscapeString;
- Context->EscapeString = gEscapeString;
- Context->MoveHighlight = gMoveHighlight;
- Context->MakeSelection = gMakeSelection;
- Context->DecNumericInput = gDecNumericInput;
- Context->HexNumericInput = gHexNumericInput;
- Context->ToggleCheckBox = gToggleCheckBox;
- Context->PromptForData = gPromptForData;
- Context->PromptForPassword = gPromptForPassword;
- Context->PromptForNewPassword = gPromptForNewPassword;
- Context->ConfirmPassword = gConfirmPassword;
- Context->ConfirmError = gConfirmError;
- Context->PassowordInvalid = gPassowordInvalid;
- Context->PressEnter = gPressEnter;
- Context->EmptyString = gEmptyString;
- Context->AreYouSure = gAreYouSure;
- Context->YesResponse = gYesResponse;
- Context->NoResponse = gNoResponse;
- Context->MiniString = gMiniString;
- Context->PlusString = gPlusString;
- Context->MinusString = gMinusString;
- Context->AdjustNumber = gAdjustNumber;
- Context->SaveChanges = gSaveChanges;
- Context->OptionMismatch = gOptionMismatch;
- Context->FormSuppress = gFormSuppress;
- Context->PromptBlockWidth = gPromptBlockWidth;
- Context->OptionBlockWidth = gOptionBlockWidth;
- Context->HelpBlockWidth = gHelpBlockWidth;
- Context->OldFormSet = gOldFormSet;
- Context->MenuRefreshHead = gMenuRefreshHead;
- Context->ProtocolNotFound = gProtocolNotFound;
-
- CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
- CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
+ Context->ExitRequired = gExitRequired;
+ Context->HiiHandle = mCurrentHiiHandle;
+
+ //
+ // Save the menu history data.
+ //
+ InitializeListHead(&Context->FormHistoryList);
+ while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ InsertTailList(&Context->FormHistoryList, &MenuList->Link);
+ }
//
// Insert to FormBrowser context list
@@ -4322,6 +4658,7 @@ RestoreBrowserContext ( {
LIST_ENTRY *Link;
BROWSER_CONTEXT *Context;
+ FORM_ENTRY_INFO *MenuList;
ASSERT (gBrowserContextCount != 0);
gBrowserContextCount--;
@@ -4340,47 +4677,19 @@ RestoreBrowserContext ( //
// Restore FormBrowser context
//
- gBannerData = Context->BannerData;
- gClassOfVfr = Context->ClassOfVfr;
- gFunctionKeySetting = Context->FunctionKeySetting;
gResetRequired = Context->ResetRequired;
- gDirection = Context->Direction;
- gEnterString = Context->EnterString;
- gEnterCommitString = Context->EnterCommitString;
- gEnterEscapeString = Context->EnterEscapeString;
- gEscapeString = Context->EscapeString;
- gMoveHighlight = Context->MoveHighlight;
- gMakeSelection = Context->MakeSelection;
- gDecNumericInput = Context->DecNumericInput;
- gHexNumericInput = Context->HexNumericInput;
- gToggleCheckBox = Context->ToggleCheckBox;
- gPromptForData = Context->PromptForData;
- gPromptForPassword = Context->PromptForPassword;
- gPromptForNewPassword = Context->PromptForNewPassword;
- gConfirmPassword = Context->ConfirmPassword;
- gConfirmError = Context->ConfirmError;
- gPassowordInvalid = Context->PassowordInvalid;
- gPressEnter = Context->PressEnter;
- gEmptyString = Context->EmptyString;
- gAreYouSure = Context->AreYouSure;
- gYesResponse = Context->YesResponse;
- gNoResponse = Context->NoResponse;
- gMiniString = Context->MiniString;
- gPlusString = Context->PlusString;
- gMinusString = Context->MinusString;
- gAdjustNumber = Context->AdjustNumber;
- gSaveChanges = Context->SaveChanges;
- gOptionMismatch = Context->OptionMismatch;
- gFormSuppress = Context->FormSuppress;
- gPromptBlockWidth = Context->PromptBlockWidth;
- gOptionBlockWidth = Context->OptionBlockWidth;
- gHelpBlockWidth = Context->HelpBlockWidth;
- gOldFormSet = Context->OldFormSet;
- gMenuRefreshHead = Context->MenuRefreshHead;
- gProtocolNotFound = Context->ProtocolNotFound;
-
- CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
- CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
+ gExitRequired = Context->ExitRequired;
+ mCurrentHiiHandle = Context->HiiHandle;
+
+ //
+ // Restore the menu history data.
+ //
+ while (!IsListEmpty (&Context->FormHistoryList)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
+ }
//
// Remove from FormBrowser context list
@@ -4440,7 +4749,7 @@ IsHiiHandleInBrowserContext ( //
// HiiHandle is Current FormSet.
//
- if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {
+ if (mCurrentHiiHandle == Handle) {
return TRUE;
}
@@ -4450,7 +4759,7 @@ IsHiiHandleInBrowserContext ( Link = GetFirstNode (&gBrowserContextList);
while (!IsNull (&gBrowserContextList, Link)) {
Context = BROWSER_CONTEXT_FROM_LINK (Link);
- if (Context->OldFormSet->HiiHandle == Handle) {
+ if (Context->HiiHandle == Handle) {
//
// HiiHandle is in BrowserContext
//
@@ -4463,6 +4772,83 @@ IsHiiHandleInBrowserContext ( }
/**
+ Perform Password check.
+ Passwork may be encrypted by driver that requires the specific check.
+
+ @param Form Form where Password Statement is in.
+ @param Statement Password statement
+ @param PasswordString Password string to be checked. It may be NULL.
+ NULL means to restore password.
+ "" string can be used to checked whether old password does exist.
+
+ @return Status Status of Password check.
+**/
+EFI_STATUS
+EFIAPI
+PasswordCheck (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_STRING PasswordString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_IFR_TYPE_VALUE IfrTypeValue;
+ FORM_BROWSER_STATEMENT *Question;
+
+ ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
+ Question = GetBrowserStatement(Statement);
+ ASSERT (Question != NULL);
+
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
+ if (ConfigAccess == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if (PasswordString == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Prepare password string in HII database
+ //
+ if (PasswordString != NULL) {
+ IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
+ } else {
+ IfrTypeValue.string = 0;
+ }
+
+ //
+ // Send password to Configuration Driver for validation
+ //
+ Status = ConfigAccess->Callback (
+ ConfigAccess,
+ EFI_BROWSER_ACTION_CHANGING,
+ Question->QuestionId,
+ Question->HiiValue.Type,
+ &IfrTypeValue,
+ &ActionRequest
+ );
+
+ //
+ // Remove password string from HII database
+ //
+ if (PasswordString != NULL) {
+ DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
+ }
+
+ return Status;
+}
+
+/**
Find the registered HotKey based on KeyData.
@param[in] KeyData A pointer to a buffer that describes the keystroke
@@ -4512,7 +4898,7 @@ SetScope ( if (Scope >= MaxLevel) {
return EFI_INVALID_PARAMETER;
}
-
+
//
// When no hot key registered in system or on the first setting,
// Scope can be set.
@@ -4637,6 +5023,128 @@ RegiserExitHandler ( }
/**
+ Check whether the browser data has been modified.
+
+ @retval TRUE Browser data is modified.
+ @retval FALSE No browser data is modified.
+
+**/
+BOOLEAN
+EFIAPI
+IsBrowserDataModified (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+
+ if (gCurrentSelection == NULL) {
+ return FALSE;
+ }
+
+ switch (gBrowserSettingScope) {
+ case FormLevel:
+ return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
+
+ case FormSetLevel:
+ return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
+
+ case SystemLevel:
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ if (IsNvUpdateRequiredForFormSet (FormSet)) {
+ return TRUE;
+ }
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ }
+ return FALSE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Execute the action requested by the Action parameter.
+
+ @param[in] Action Execute the request action.
+ @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
+
+ @retval EFI_SUCCESS Execute the request action succss.
+ @retval EFI_INVALID_PARAMETER The input action value is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+ExecuteAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ )
+{
+ EFI_STATUS Status;
+
+ if (gCurrentSelection == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Executet the discard action.
+ //
+ if ((Action & BROWSER_ACTION_DISCARD) != 0) {
+ Status = DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Executet the difault action.
+ //
+ if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
+ Status = ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Executet the submit action.
+ //
+ if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
+ Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Executet the reset action.
+ //
+ if ((Action & BROWSER_ACTION_RESET) != 0) {
+ gResetRequired = TRUE;
+ }
+
+ //
+ // Executet the exit action.
+ //
+ if ((Action & BROWSER_ACTION_EXIT) != 0) {
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (gBrowserSettingScope == SystemLevel) {
+ if (ExitHandlerFunction != NULL) {
+ ExitHandlerFunction ();
+ }
+ }
+
+ gExitRequired = TRUE;
+ }
+
+ return Status;
+}
+
+/**
Create reminder to let user to choose save or discard the changed browser data.
Caller can use it to actively check the changed browser data.
@@ -4655,12 +5163,6 @@ SaveReminder ( FORM_BROWSER_FORMSET *FormSet;
BOOLEAN IsDataChanged;
UINT32 DataSavedAction;
- CHAR16 *YesResponse;
- CHAR16 *NoResponse;
- CHAR16 *EmptyString;
- CHAR16 *ChangeReminderString;
- CHAR16 *SaveConfirmString;
- EFI_INPUT_KEY Key;
DataSavedAction = BROWSER_NO_CHANGES;
IsDataChanged = FALSE;
@@ -4671,7 +5173,7 @@ SaveReminder ( if (!ValidateFormSet(FormSet)) {
continue;
}
- if (IsNvUpdateRequired (FormSet)) {
+ if (IsNvUpdateRequiredForFormSet (FormSet)) {
IsDataChanged = TRUE;
break;
}
@@ -4685,42 +5187,19 @@ SaveReminder ( }
//
- // If data is changed, prompt user
+ // If data is changed, prompt user to save or discard it.
//
- gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-
- YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
- ASSERT (YesResponse != NULL);
- NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
- ASSERT (NoResponse != NULL);
- EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
- ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);
- SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);
-
do {
- CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);
- } while
- (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))
- );
+ DataSavedAction = (UINT32) mFormDisplay->ConfirmDataChange();
- //
- // If the user hits the YesResponse key
- //
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {
- SubmitForm (NULL, NULL, SystemLevel);
- DataSavedAction = BROWSER_SAVE_CHANGES;
- } else {
- DiscardForm (NULL, NULL, SystemLevel);
- DataSavedAction = BROWSER_DISCARD_CHANGES;
- gResetRequired = FALSE;
- }
-
- FreePool (YesResponse);
- FreePool (NoResponse);
- FreePool (EmptyString);
- FreePool (SaveConfirmString);
- FreePool (ChangeReminderString);
+ if (DataSavedAction == BROWSER_SAVE_CHANGES) {
+ SubmitForm (NULL, NULL, SystemLevel);
+ break;
+ } else if (DataSavedAction == BROWSER_DISCARD_CHANGES) {
+ DiscardForm (NULL, NULL, SystemLevel);
+ break;
+ }
+ } while (1);
return DataSavedAction;
}
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 9a0c739094..1be2c0d5a0 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -22,7 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <Protocol/SimpleTextOut.h>
#include <Protocol/SimpleTextIn.h>
#include <Protocol/FormBrowser2.h>
-#include <Protocol/FormBrowserEx.h>
+#include <Protocol/FormBrowserEx2.h>
+#include <Protocol/DisplayProtocol.h>
#include <Protocol/DevicePath.h>
#include <Protocol/UnicodeCollation.h>
#include <Protocol/HiiConfigAccess.h>
@@ -47,106 +48,29 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <Library/HiiLib.h>
#include <Library/PcdLib.h>
#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
-#include "Colors.h"
//
// This is the generated header file which includes whatever needs to be exported (strings + IFR)
//
-extern UINT8 SetupBrowserStrings[];
+#define UI_ACTION_NONE 0
+#define UI_ACTION_REFRESH_FORM 1
+#define UI_ACTION_REFRESH_FORMSET 2
+#define UI_ACTION_EXIT 3
//
-// Screen definitions
-//
-#define BANNER_HEIGHT 6
-#define BANNER_COLUMNS 3
-#define BANNER_LEFT_COLUMN_INDENT 1
-
-#define FRONT_PAGE_HEADER_HEIGHT 6
-#define NONE_FRONT_PAGE_HEADER_HEIGHT 3
-#define LEFT_SKIPPED_COLUMNS 3
-#define FOOTER_HEIGHT 4
-#define STATUS_BAR_HEIGHT 1
-#define SCROLL_ARROW_HEIGHT 1
-#define POPUP_PAD_SPACE_COUNT 5
-#define POPUP_FRAME_WIDTH 2
-
-//
-// Definition for function key setting
-//
-#define NONE_FUNCTION_KEY_SETTING 0
-#define ENABLE_FUNCTION_KEY_SETTING 1
-
-typedef struct {
- EFI_GUID FormSetGuid;
- UINTN KeySetting;
-} FUNCTIION_KEY_SETTING;
-
-//
-// Character definitions
-//
-#define CHAR_SPACE 0x0020
-#define UPPER_LOWER_CASE_OFFSET 0x20
-
//
// Time definitions
//
#define ONE_SECOND 10000000
-//
-// Display definitions
-//
-#define LEFT_HYPER_DELIMITER L'<'
-#define RIGHT_HYPER_DELIMITER L'>'
-
-#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 YES_ANSWER L'Y'
-#define NO_ANSWER L'N'
-
-//
-// This is the Input Error Message
-//
-#define INPUT_ERROR 1
-
-//
-// This is the NV RAM update required Message
-//
-#define NV_UPDATE_REQUIRED 2
-
-//
-// Refresh the Status Bar with flags
-//
-#define REFRESH_STATUS_BAR 0xff
-
-//
// Incremental string lenght of ConfigRequest
//
#define CONFIG_REQUEST_STRING_INCREMENTAL 1024
//
-// HII value compare result
-//
-#define HII_VALUE_UNDEFINED 0
-#define HII_VALUE_EQUAL 1
-#define HII_VALUE_LESS_THAN 2
-#define HII_VALUE_GREATER_THAN 3
-
-//
// Incremental size of stack for expression
//
#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
@@ -163,15 +87,12 @@ typedef struct { //
// Produced protocol
//
- EFI_FORM_BROWSER2_PROTOCOL FormBrowser2;
-
- EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx;
+ EFI_FORM_BROWSER2_PROTOCOL FormBrowser2;
+ EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx;
-} SETUP_DRIVER_PRIVATE_DATA;
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2;
-typedef struct {
- EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS];
-} BANNER_DATA;
+} SETUP_DRIVER_PRIVATE_DATA;
//
// IFR relative definition
@@ -194,16 +115,6 @@ typedef struct { #define FORM_INCONSISTENT_VALIDATION 0
#define FORM_NO_SUBMIT_VALIDATION 1
-#define FORMSET_CLASS_PLATFORM_SETUP 0x0001
-#define FORMSET_CLASS_FRONT_PAGE 0x0002
-
-typedef struct {
- UINT8 Type;
- UINT8 *Buffer;
- UINT16 BufferLen;
- EFI_IFR_TYPE_VALUE Value;
-} EFI_HII_VALUE;
-
#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T')
typedef struct {
@@ -255,6 +166,7 @@ typedef struct { BROWSER_STORAGE *BrowserStorage;
CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
+ CHAR16 *ConfigElements;// Elements need to load initial data.
UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest>
UINTN SpareStrLen; // Spare length of ConfigRequest string buffer
} FORMSET_STORAGE;
@@ -344,6 +256,8 @@ typedef struct { typedef struct {
UINTN Signature;
LIST_ENTRY Link;
+
+ EFI_IFR_ONE_OF_OPTION *OpCode; // OneOfOption Data
EFI_STRING_ID Text;
UINT8 Flags;
@@ -376,6 +290,7 @@ typedef struct { LIST_ENTRY Link;
UINT8 Operand; // The operand (first byte) of this Statement or Question
+ EFI_IFR_OP_HEADER *OpCode;
//
// Statement Header
@@ -385,6 +300,11 @@ typedef struct { EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT
//
+ // Fake Question Id, used for statement not has true QuestionId.
+ //
+ EFI_QUESTION_ID FakeQuestionId;
+
+ //
// Question Header
//
EFI_QUESTION_ID QuestionId; // The value of zero is reserved
@@ -417,6 +337,7 @@ typedef struct { EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON
EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID
BOOLEAN Locked; // Whether this statement is locked.
+ BOOLEAN ValueChanged; // Whether this statement's value is changed.
//
// Get from IFR parsing
//
@@ -467,8 +388,6 @@ typedef struct { BOOLEAN ModalForm; // Whether this is a modal form.
BOOLEAN Locked; // Whether this form is locked.
- BOOLEAN NvUpdateRequired; // Whether this form has NV update request.
-
LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT)
LIST_ENTRY ConfigRequestHead; // List of configreques for all storage.
@@ -502,6 +421,7 @@ typedef struct { UINTN IfrBinaryLength;
UINT8 *IfrBinaryData;
+ BOOLEAN QuestionInited; // Have finished question initilization?
EFI_GUID Guid;
EFI_STRING_ID FormSetTitle;
EFI_STRING_ID Help;
@@ -514,14 +434,21 @@ typedef struct { FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions
EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode
+ LIST_ENTRY StatementListOSF; // Statement list out side of the form.
LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE)
LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM)
LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
} FORM_BROWSER_FORMSET;
-
#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_EVENT RefreshEvent;
+} FORM_BROWSER_REFRESH_EVENT_NODE;
+
+#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link)
+
#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X')
typedef struct {
@@ -531,67 +458,54 @@ typedef struct { //
// Globals defined in Setup.c
//
- BANNER_DATA *BannerData;
- UINTN ClassOfVfr;
- UINTN FunctionKeySetting;
- BOOLEAN ResetRequired;
- UINT16 Direction;
- EFI_SCREEN_DESCRIPTOR ScreenDimensions;
- CHAR16 *EnterString;
- CHAR16 *EnterCommitString;
- CHAR16 *EnterEscapeString;
- CHAR16 *EscapeString;
- CHAR16 *MoveHighlight;
- CHAR16 *MakeSelection;
- CHAR16 *DecNumericInput;
- CHAR16 *HexNumericInput;
- CHAR16 *ToggleCheckBox;
- CHAR16 *PromptForData;
- CHAR16 *PromptForPassword;
- CHAR16 *PromptForNewPassword;
- CHAR16 *ConfirmPassword;
- CHAR16 *ConfirmError;
- CHAR16 *PassowordInvalid;
- CHAR16 *PressEnter;
- CHAR16 *EmptyString;
- CHAR16 *AreYouSure;
- CHAR16 *YesResponse;
- CHAR16 *NoResponse;
- CHAR16 *MiniString;
- CHAR16 *PlusString;
- CHAR16 *MinusString;
- CHAR16 *AdjustNumber;
- CHAR16 *SaveChanges;
- CHAR16 *OptionMismatch;
- CHAR16 *FormSuppress;
- CHAR16 *ProtocolNotFound;
- CHAR16 PromptBlockWidth;
- CHAR16 OptionBlockWidth;
- CHAR16 HelpBlockWidth;
- FORM_BROWSER_FORMSET *OldFormSet;
+ BOOLEAN ResetRequired;
+ BOOLEAN ExitRequired;
+ EFI_HII_HANDLE HiiHandle;
- //
- // Globals defined in Ui.c
- //
- LIST_ENTRY MenuOption;
- VOID *MenuRefreshHead;
+ LIST_ENTRY FormHistoryList;
} BROWSER_CONTEXT;
#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE)
-#define BROWSER_HOT_KEY_SIGNATURE SIGNATURE_32 ('B', 'H', 'K', 'S')
-
typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- EFI_INPUT_KEY *KeyData;
- IN UINT32 Action;
- IN UINT16 DefaultId;
- IN EFI_STRING HelpString;
-} BROWSER_HOT_KEY;
+ EFI_HII_HANDLE Handle;
-#define BROWSER_HOT_KEY_FROM_LINK(a) CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE)
+ //
+ // Target formset/form/Question information
+ //
+ EFI_GUID FormSetGuid;
+ UINT16 FormId;
+ UINT16 QuestionId;
+ UINTN Sequence; // used for time/date only.
+
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN PromptCol;
+ UINTN OptionCol;
+ UINTN CurrentRow;
+
+ //
+ // Ation for Browser to taken:
+ // UI_ACTION_NONE - navigation inside a form
+ // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form
+ // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary
+ //
+ UINTN Action;
+
+ //
+ // Current selected fomset/form/Question
+ //
+ FORM_BROWSER_FORMSET *FormSet;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ //
+ // Whether the Form is editable
+ //
+ BOOLEAN FormEditable;
+
+ FORM_ENTRY_INFO *CurrentMenu;
+} UI_MENU_SELECTION;
//
// Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll.
@@ -614,72 +528,32 @@ typedef enum { } GET_SET_QUESTION_VALUE_WITH;
extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
-extern EFI_HII_STRING_PROTOCOL *mHiiString;
extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
+extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
-extern BANNER_DATA *gBannerData;
-extern EFI_HII_HANDLE gFrontPageHandle;
-extern UINTN gClassOfVfr;
-extern UINTN gFunctionKeySetting;
extern BOOLEAN gResetRequired;
-extern EFI_HII_HANDLE gHiiHandle;
-extern UINT16 gDirection;
-extern EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+extern BOOLEAN gExitRequired;
extern FORM_BROWSER_FORMSET *gOldFormSet;
extern LIST_ENTRY gBrowserFormSetList;
extern LIST_ENTRY gBrowserHotKeyList;
extern BROWSER_SETTING_SCOPE gBrowserSettingScope;
extern EXIT_HANDLER ExitHandlerFunction;
-extern UINTN gFooterHeight;
-
+extern EFI_HII_HANDLE mCurrentHiiHandle;
//
// Browser Global Strings
//
-extern CHAR16 *gDiscardFailed;
-extern CHAR16 *gDefaultFailed;
-extern CHAR16 *gEnterString;
-extern CHAR16 *gEnterCommitString;
-extern CHAR16 *gEnterEscapeString;
-extern CHAR16 *gEscapeString;
-extern CHAR16 *gSaveFailed;
-extern CHAR16 *gMoveHighlight;
-extern CHAR16 *gMakeSelection;
-extern CHAR16 *gDecNumericInput;
-extern CHAR16 *gHexNumericInput;
-extern CHAR16 *gToggleCheckBox;
-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 *gAreYouSure;
-extern CHAR16 *gYesResponse;
-extern CHAR16 *gNoResponse;
-extern CHAR16 *gMiniString;
-extern CHAR16 *gPlusString;
-extern CHAR16 *gMinusString;
-extern CHAR16 *gAdjustNumber;
-extern CHAR16 *gSaveChanges;
-extern CHAR16 *gOptionMismatch;
-extern CHAR16 *gFormSuppress;
-extern CHAR16 *gProtocolNotFound;
-
-extern CHAR16 gPromptBlockWidth;
-extern CHAR16 gOptionBlockWidth;
-extern CHAR16 gHelpBlockWidth;
extern EFI_GUID gZeroGuid;
-extern EFI_GUID gTianoHiiIfrGuid;
-#include "Ui.h"
+extern UI_MENU_SELECTION *gCurrentSelection;
+
//
// Global Procedure Defines
//
+#include "Expression.h"
/**
Initialize the HII String Token to the correct values.
@@ -691,91 +565,6 @@ InitializeBrowserStrings ( );
/**
- Prints a unicode string to the default console,
- using L"%s" format.
-
- @param String String pointer.
-
- @return Length of string printed to the console
-
-**/
-UINTN
-PrintString (
- IN CHAR16 *String
- );
-
-/**
- Prints a chracter to the default console,
- using L"%c" format.
-
- @param Character Character to print.
-
- @return Length of string printed to the console.
-
-**/
-UINTN
-PrintChar (
- CHAR16 Character
- );
-
-/**
- Prints a formatted unicode string to the default console, at
- the supplied cursor position.
-
- @param Column The cursor position to print the string at.
- @param Row The cursor position to print the string at
- @param Fmt Format string
- @param ... Variable argument list for formating string.
-
- @return Length of string printed to the console
-
-**/
-UINTN
-EFIAPI
-PrintAt (
- IN UINTN Column,
- IN UINTN Row,
- IN CHAR16 *Fmt,
- ...
- );
-
-/**
- Prints a unicode string to the default console, at
- the supplied cursor position, using L"%s" format.
-
- @param Column The cursor position to print the string at.
- @param Row The cursor position to print the string at
- @param String String pointer.
-
- @return Length of string printed to the console
-
-**/
-UINTN
-PrintStringAt (
- IN UINTN Column,
- IN UINTN Row,
- IN CHAR16 *String
- );
-
-/**
- Prints a chracter to the default console, at
- the supplied cursor position, using L"%c" format.
-
- @param Column The cursor position to print the string at.
- @param Row The cursor position to print the string at.
- @param Character Character to print.
-
- @return Length of string printed to the console.
-
-**/
-UINTN
-PrintCharAt (
- IN UINTN Column,
- IN UINTN Row,
- CHAR16 Character
- );
-
-/**
Parse opcodes in the formset IFR binary.
@param FormSet Pointer of the FormSet data structure.
@@ -800,17 +589,6 @@ DestroyFormSet ( IN OUT FORM_BROWSER_FORMSET *FormSet
);
-/**
- This function displays the page frame.
-
- @param Selection Selection contains the information about
- the Selection, form and formset to be displayed.
- Selection action may be updated in retrieve callback.
-**/
-VOID
-DisplayPageFrame (
- IN UI_MENU_SELECTION *Selection
- );
/**
Create a new string in HII Package List.
@@ -860,59 +638,6 @@ GetToken ( );
/**
- 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
- );
-
-/**
- Routine used to abstract a generic dialog interface and return the selected key or string
-
- @param NumberOfLines The number of lines for the dialog box
- @param HotKey Defines whether a single character is parsed
- (TRUE) and returned in KeyValue or a string is
- returned in StringBuffer. Two special characters
- are considered when entering a string, a SCAN_ESC
- and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
- string input and returns
- @param MaximumStringSize The maximum size in bytes of a typed in string
- (each character is a CHAR16) and the minimum
- string returned is two bytes
- @param StringBuffer The passed in pointer to the buffer which will
- hold the typed in string if HotKey is FALSE
- @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
- @param ... A series of (quantity == NumberOfLines) text
- strings which will be used to construct the dialog
- box
-
- @retval EFI_SUCCESS Displayed dialog and received user interaction
- @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
- (StringBuffer == NULL) && (HotKey == FALSE))
- @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
-
-**/
-EFI_STATUS
-EFIAPI
-CreateDialog (
- IN UINTN NumberOfLines,
- IN BOOLEAN HotKey,
- IN UINTN MaximumStringSize,
- OUT CHAR16 *StringBuffer,
- OUT EFI_INPUT_KEY *KeyValue,
- ...
- );
-
-/**
Get Value for given Name from a NameValue Storage.
@param Storage The NameValue Storage.
@@ -939,6 +664,7 @@ GetValueByName ( @param Name The Name.
@param Value The Value to set.
@param SetValueTo Whether update editValue or Value.
+ @param ReturnNode The node use the input name.
@retval EFI_SUCCESS Value found for given Name.
@retval EFI_NOT_FOUND No such Name found in NameValue storage.
@@ -946,10 +672,31 @@ GetValueByName ( **/
EFI_STATUS
SetValueByName (
- IN BROWSER_STORAGE *Storage,
- IN CHAR16 *Name,
- IN CHAR16 *Value,
- IN GET_SET_QUESTION_VALUE_WITH SetValueTo
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN CHAR16 *Value,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
+ OUT NAME_VALUE_NODE **ReturnNode
+ );
+
+/**
+ Validate whether this question's value has changed.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval TRUE Question's value has changed.
+ @retval FALSE Question's value has not changed
+
+**/
+BOOLEAN
+IsQuestionValueChanged (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
);
/**
@@ -1071,10 +818,8 @@ GetQuestionDefault ( @param FormSet FormSet data structure.
- @retval EFI_SUCCESS The function completed successfully.
-
**/
-EFI_STATUS
+VOID
InitializeCurrentSetting (
IN OUT FORM_BROWSER_FORMSET *FormSet
);
@@ -1087,7 +832,6 @@ InitializeCurrentSetting ( GUID), take the first FormSet found in package
list.
@param FormSet FormSet data structure.
- @param UpdateGlobalVar Whether need to update the global variable.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND The specified FormSet could not be found.
@@ -1097,8 +841,7 @@ EFI_STATUS InitializeFormSet (
IN EFI_HII_HANDLE Handle,
IN OUT EFI_GUID *FormSetGuid,
- OUT FORM_BROWSER_FORMSET *FormSet,
- IN BOOLEAN UpdateGlobalVar
+ OUT FORM_BROWSER_FORMSET *FormSet
);
/**
@@ -1176,6 +919,7 @@ LoadFormSetConfig ( @param Storage The Storage to be conveted.
@param ConfigResp The returned <ConfigResp>.
@param ConfigRequest The ConfigRequest string.
+ @param GetEditBuf Get the data from editbuffer or buffer.
@retval EFI_SUCCESS Convert success.
@retval EFI_INVALID_PARAMETER Incorrect storage type.
@@ -1185,7 +929,8 @@ EFI_STATUS StorageToConfigResp (
IN BROWSER_STORAGE *Storage,
IN CHAR16 **ConfigResp,
- IN CHAR16 *ConfigRequest
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN GetEditBuf
);
/**
@@ -1210,10 +955,8 @@ ConfigRespToStorage ( @param FormSet FormSet data structure.
@param Storage Buffer Storage.
- @retval EFI_SUCCESS The function completed successfully.
-
**/
-EFI_STATUS
+VOID
LoadStorage (
IN FORM_BROWSER_FORMSET *FormSet,
IN FORMSET_STORAGE *Storage
@@ -1349,30 +1092,29 @@ BrowserCallback ( about the Selection, form and formset to be displayed.
On output, Selection return the screen item that is selected
by user.
- @param Repaint Whether need to repaint the menu.
- @param NewLine Whether need to show at new line.
+ @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
+ else, we need to exit current formset.
- @retval TRUE Need return.
- @retval FALSE No need to return.
+ @retval TRUE Exit current form.
+ @retval FALSE User press ESC and keep in current form.
**/
BOOLEAN
FindNextMenu (
- IN OUT UI_MENU_SELECTION *Selection,
- IN BOOLEAN *Repaint,
- IN BOOLEAN *NewLine
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE SettingLevel
);
/**
- check whether the formset need to update the NV.
+ check whether the form need to update the NV.
- @param FormSet FormSet data structure.
- @param SetValue Whether set new value or clear old value.
+ @param Form Form data structure.
+ @retval TRUE Need to update the NV.
+ @retval FALSE No need to update the NV.
**/
-VOID
-UpdateNvInfoInForm (
- IN FORM_BROWSER_FORMSET *FormSet,
- IN BOOLEAN SetValue
+BOOLEAN
+IsNvUpdateRequiredForForm (
+ IN FORM_BROWSER_FORM *Form
);
/**
@@ -1383,12 +1125,25 @@ UpdateNvInfoInForm ( @retval TRUE Need to update the NV.
@retval FALSE No need to update the NV.
**/
-BOOLEAN
-IsNvUpdateRequired (
+BOOLEAN
+IsNvUpdateRequiredForFormSet (
IN FORM_BROWSER_FORMSET *FormSet
);
/**
+ Check whether the storage data for current form set is changed.
+
+ @param FormSet FormSet data structure.
+
+ @retval TRUE Data is changed.
+ @retval FALSE Data is not changed.
+**/
+BOOLEAN
+IsStorageDataChangedForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
Call the call back function for the question and process the return action.
@param Selection On input, Selection tell setup browser the information
@@ -1517,6 +1272,38 @@ RegiserExitHandler ( );
/**
+
+ Check whether the browser data has been modified.
+
+ @retval TRUE Browser data is changed.
+ @retval FALSE No browser data is changed.
+
+**/
+BOOLEAN
+EFIAPI
+IsBrowserDataModified (
+ VOID
+ );
+
+/**
+
+ Execute the action requested by the Action parameter.
+
+ @param[in] Action Execute the request action.
+ @param[in] DefaultId The default Id info when need to load default value.
+
+ @retval EFI_SUCCESS Execute the request action succss.
+ @retval EFI_INVALID_PARAMETER The input action value is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+ExecuteAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ );
+
+/**
Create reminder to let user to choose save or discard the changed browser data.
Caller can use it to actively check the changed browser data.
@@ -1545,6 +1332,267 @@ GetHotKeyFromRegisterList ( );
/**
+
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ );
+
+/**
+ Password may be stored as encrypted by Configuration Driver. When change a
+ password, user will be challenged with old password. To validate user input old
+ password, we will send the clear text to Configuration Driver via Callback().
+ Configuration driver is responsible to check the passed in password and return
+ the validation result. If validation pass, state machine in password Callback()
+ will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
+ After user type in new password twice, Callback() will be invoked to send the
+ new password to Configuration Driver.
+
+ @param Selection Pointer to UI_MENU_SELECTION.
+ @param MenuOption The MenuOption for this password Question.
+ @param String The clear text of password.
+
+ @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
+ @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
+ @retval EFI_SUCCESS Password correct, Browser will prompt for new
+ password.
+ @retval EFI_NOT_READY Password incorrect, Browser will show error
+ message.
+ @retval Other Browser will do nothing.
+ @return In state of BROWSER_STATE_SET_PASSWORD:
+ @retval EFI_SUCCESS Set password success.
+ @retval Other Set password failed.
+
+**/
+EFI_STATUS
+PasswordCallback (
+ IN UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16 *String
+ );
+
+/**
+ Display error message for invalid password.
+
+**/
+VOID
+PasswordInvalid (
+ VOID
+ );
+
+/**
+ The worker function that send the displays to the screen. On output,
+ the selection made by user is returned.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+
+ @retval EFI_SUCCESS The page is displayed successfully.
+ @return Other value if the page failed to be diplayed.
+
+**/
+EFI_STATUS
+SetupBrowser (
+ IN OUT UI_MENU_SELECTION *Selection
+ );
+
+/**
+ Free up the resource allocated for all strings required
+ by Setup Browser.
+
+**/
+VOID
+FreeBrowserStrings (
+ VOID
+ );
+
+/**
+ Create a menu with specified formset GUID and form ID, and add it as a child
+ of the given parent menu.
+
+ @param HiiHandle Hii handle related to this formset.
+ @param FormSetGuid The Formset Guid of menu to be added.
+ @param FormId The Form ID of menu to be added.
+ @param QuestionId The question id of this menu to be added.
+
+ @return A pointer to the newly added menu or NULL if memory is insufficient.
+
+**/
+FORM_ENTRY_INFO *
+UiAddMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId,
+ IN UINT16 QuestionId
+ );
+
+/**
+ Search Menu with given FormSetGuid and FormId in all cached menu list.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+ @param FormId The Form ID of menu to search.
+
+ @return A pointer to menu found or NULL if not found.
+
+**/
+FORM_ENTRY_INFO *
+UiFindMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId
+ );
+
+/**
+ Free Menu list linked list.
+
+ @param MenuListHead One Menu list point in the menu list.
+
+**/
+VOID
+UiFreeMenuList (
+ LIST_ENTRY *MenuListHead
+ );
+
+/**
+ Find parent menu for current menu.
+
+ @param CurrentMenu Current Menu
+
+ @retval The parent menu for current menu.
+**/
+FORM_ENTRY_INFO *
+UiFindParentMenu (
+ IN FORM_ENTRY_INFO *CurrentMenu
+ );
+
+/**
+ 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.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ );
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Perform Password check.
+ Passwork may be encrypted by driver that requires the specific check.
+
+ @param Form Form where Password Statement is in.
+ @param Statement Password statement
+ @param PasswordString Password string to be checked. It may be NULL.
+ NULL means to restore password.
+ "" string can be used to checked whether old password does exist.
+
+ @return Status Status of Password check.
+**/
+EFI_STATUS
+EFIAPI
+PasswordCheck (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_STRING PasswordString OPTIONAL
+ );
+
+/**
+
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ );
+
+/**
+
+ Initialize the Display form structure data.
+
+**/
+VOID
+InitializeDisplayFormData (
+ VOID
+ );
+
+
+/**
Base on the current formset info, clean the ConfigRequest string in browser storage.
@param FormSet Pointer of the FormSet
@@ -1554,5 +1602,5 @@ VOID CleanBrowserStorage (
IN OUT FORM_BROWSER_FORMSET *FormSet
);
-
+
#endif
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf index 7e740bc099..395c9383d5 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -19,7 +19,7 @@ BASE_NAME = SetupBrowser
FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671
MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
+ VERSION_STRING = 2.0
ENTRY_POINT = InitializeSetup
#
@@ -29,19 +29,12 @@ #
[Sources]
- SetupBrowserStr.uni
Setup.c
Setup.h
IfrParse.c
Expression.c
- InputHandler.c
- Print.c
Presentation.c
- ProcessOptions.c
- Ui.c
- Ui.h
- Colors.h
-
+ Expression.h
[Packages]
MdePkg/MdePkg.dec
@@ -59,36 +52,31 @@ HiiLib
DevicePathLib
PcdLib
+ UefiLib
[Guids]
- gEfiIfrTianoGuid ## CONSUMES ## GUID
gEfiIfrFrameworkGuid ## CONSUMES ## GUID
gEfiHiiPlatformSetupFormsetGuid
gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID
[Protocols]
gEfiHiiConfigAccessProtocolGuid ## CONSUMES
- gEfiHiiStringProtocolGuid ## CONSUMES
gEfiFormBrowser2ProtocolGuid ## PRODUCES
- gEfiFormBrowserExProtocolGuid ## PRODUCES
+ gEdkiiFormBrowserEx2ProtocolGuid ## PRODUCES
gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
gEfiHiiDatabaseProtocolGuid ## CONSUMES
gEfiUnicodeCollation2ProtocolGuid ## CONSUMES
gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
gEfiDevicePathFromTextProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiFormDisplayEngineProtocolGuid ## PRODUCE
+ gEfiFormBrowserExProtocolGuid ## PRODUCE
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES
-
-[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor ## CONSUMES
[Depex]
gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+[BuildOptions]
+ MSFT:*_*_*_CC_FLAGS = /Od
|