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