]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
Clean the useless code.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
index a07cc75a47c2c44755a268bf5119d0f1cf9695c4..6d0dd2569cad938fdb2883ff8ee5b96ce2e0c07d 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Entry and initialization module for the browser.\r
 \r
-Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -117,6 +117,12 @@ CHAR16            *gFormNotFound;
 CHAR16            *gNoSubmitIf;\r
 CHAR16            *gBrwoserError;\r
 CHAR16            *gSaveFailed;\r
+CHAR16            *gNoSubmitIfFailed;\r
+CHAR16            *gSaveProcess;\r
+CHAR16            *gSaveNoSubmitProcess;\r
+CHAR16            *gDiscardChange;\r
+CHAR16            *gJumpToFormSet;\r
+CHAR16            *gCheckError;\r
 CHAR16            *gPromptForData;\r
 CHAR16            *gPromptForPassword;\r
 CHAR16            *gPromptForNewPassword;\r
@@ -130,6 +136,7 @@ CHAR16            *gOptionMismatch;
 CHAR16            *gFormSuppress;\r
 CHAR16            *gProtocolNotFound;\r
 \r
+CHAR16            gModalSkipColumn;\r
 CHAR16            gPromptBlockWidth;\r
 CHAR16            gOptionBlockWidth;\r
 CHAR16            gHelpBlockWidth;\r
@@ -185,6 +192,12 @@ InitializeDisplayStrings (
 {\r
   mUnknownString        = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);\r
   gSaveFailed           = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);\r
+  gNoSubmitIfFailed     = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle);\r
+  gSaveProcess          = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle);\r
+  gSaveNoSubmitProcess  = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle);\r
+  gDiscardChange        = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle);\r
+  gJumpToFormSet        = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle);\r
+  gCheckError           = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle);\r
   gPromptForData        = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
   gPromptForPassword    = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);\r
   gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);\r
@@ -215,6 +228,12 @@ FreeDisplayStrings (
   FreePool (mUnknownString);\r
   FreePool (gEmptyString);\r
   FreePool (gSaveFailed);\r
+  FreePool (gNoSubmitIfFailed);\r
+  FreePool (gSaveProcess);\r
+  FreePool (gSaveNoSubmitProcess);\r
+  FreePool (gDiscardChange);\r
+  FreePool (gJumpToFormSet);\r
+  FreePool (gCheckError);\r
   FreePool (gPromptForData);\r
   FreePool (gPromptForPassword);\r
   FreePool (gPromptForNewPassword);\r
@@ -258,20 +277,35 @@ GetPrompt (
 /**\r
   Get the supported width for a particular op-code\r
 \r
-  @param  Statement              The curent statement.\r
+  @param  MenuOption             The menu option.\r
+  @param  AdjustWidth            The width which is saved for the space.\r
 \r
   @return Returns the number of CHAR16 characters that is support.\r
 \r
 **/\r
 UINT16\r
 GetWidth (\r
-  IN FORM_DISPLAY_ENGINE_STATEMENT        *Statement\r
+  IN  UI_MENU_OPTION     *MenuOption,\r
+  OUT UINT16             *AdjustWidth\r
   )\r
 {\r
-  CHAR16       *String;\r
-  UINTN        Size;\r
-  UINT16       Width;\r
-  EFI_IFR_TEXT *TestOp;\r
+  CHAR16                        *String;\r
+  UINTN                         Size;\r
+  EFI_IFR_TEXT                  *TestOp;\r
+  UINT16                        ReturnWidth;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+\r
+  Statement = MenuOption->ThisTag;\r
+\r
+  //\r
+  // For modal form, clean the entire row.\r
+  //\r
+  if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+    if (AdjustWidth  != NULL) {\r
+      *AdjustWidth = LEFT_SKIPPED_COLUMNS;\r
+    }\r
+    return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gModalSkipColumn + LEFT_SKIPPED_COLUMNS));\r
+  }\r
 \r
   Size = 0;\r
 \r
@@ -297,12 +331,33 @@ GetWidth (
       //\r
       ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))\r
       ) {\r
-    Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
+    \r
+    //\r
+    // Return the space width.\r
+    // \r
+    if (AdjustWidth != NULL) {\r
+      *AdjustWidth = 2;\r
+    }\r
+    //\r
+    // Keep consistent with current behavior.\r
+    //\r
+    ReturnWidth = (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);\r
   } else {\r
-    Width = (UINT16) gPromptBlockWidth;\r
+    if (AdjustWidth != NULL) {\r
+      *AdjustWidth = 1;\r
+    }\r
+\r
+    ReturnWidth =  (UINT16) (gPromptBlockWidth - 1);\r
+  }\r
+\r
+  //\r
+  // For nest in statement, should the subtitle indent.\r
+  //\r
+  if (MenuOption->NestInStatement) {\r
+    ReturnWidth -= SUBTITLE_INDENT;\r
   }\r
 \r
-  return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
+  return ReturnWidth;\r
 }\r
 \r
 /**\r
@@ -516,24 +571,7 @@ UiAddMenuOption (
   String = GetToken (PromptId, gFormData->HiiHandle);\r
   ASSERT (String != NULL);\r
 \r
-  Width  = GetWidth (Statement);\r
-  for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {\r
-    //\r
-    // If there is more string to process print on the next row and increment the Skip value\r
-    //\r
-    if (StrLen (&String[ArrayEntry]) != 0) {\r
-      NumberOfLines++;\r
-    }\r
-    FreePool (OutputString);\r
-  }\r
-\r
   if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
-    //\r
-    // Add three MenuOptions for Date/Time\r
-    // Data format :      [01/02/2004]      [11:22:33]\r
-    // Line number :        0  0    1         0  0  1\r
-    //\r
-    NumberOfLines = 0;\r
     Count = 3;\r
   }\r
 \r
@@ -548,14 +586,6 @@ UiAddMenuOption (
     MenuOption->NestInStatement = NestIn;\r
     MenuOption->EntryNumber = *MenuItemCount;\r
 \r
-    if (Index == 2) {\r
-      //\r
-      // Override LineNumber for the MenuOption in Date/Time sequence\r
-      //\r
-      MenuOption->Skip = 1;\r
-    } else {\r
-      MenuOption->Skip = NumberOfLines;\r
-    }\r
     MenuOption->Sequence = Index;\r
 \r
     if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {\r
@@ -610,6 +640,37 @@ UiAddMenuOption (
       }\r
     }\r
 \r
+    if (Index == 0 && \r
+      (Statement->OpCode->OpCode != EFI_IFR_DATE_OP) && \r
+      (Statement->OpCode->OpCode != EFI_IFR_TIME_OP)) {\r
+      Width  = GetWidth (MenuOption, NULL);\r
+      for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {\r
+        //\r
+        // If there is more string to process print on the next row and increment the Skip value\r
+        //\r
+        if (StrLen (&String[ArrayEntry]) != 0) {\r
+          NumberOfLines++;\r
+        }\r
+        FreePool (OutputString);\r
+      }\r
+    } else {\r
+      //\r
+      // Add three MenuOptions for Date/Time\r
+      // Data format :      [01/02/2004]      [11:22:33]\r
+      // Line number :        0  0    1         0  0  1\r
+      //    \r
+      NumberOfLines = 0;\r
+    }\r
+\r
+    if (Index == 2) {\r
+      //\r
+      // Override LineNumber for the MenuOption in Date/Time sequence\r
+      //\r
+      MenuOption->Skip = 1;\r
+    } else {\r
+      MenuOption->Skip = NumberOfLines;\r
+    }\r
+\r
     InsertTailList (&gMenuOption, &MenuOption->Link);\r
   }\r
 \r
@@ -656,6 +717,13 @@ ConvertStatementToMenu (
       NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);\r
       NestLink = GetNextNode (&Statement->NestStatementList, NestLink);\r
 \r
+      //\r
+      // Skip the opcode not recognized by Display core.\r
+      //\r
+      if (NestStatement->OpCode->OpCode == EFI_IFR_GUID_OP) {\r
+        continue;\r
+      }\r
+\r
       UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);\r
     }\r
   }\r
@@ -809,6 +877,54 @@ UpdateOptionSkipLines (
   }\r
 }\r
 \r
+/**\r
+  Check whether this Menu Option could be print.\r
+\r
+  Check Prompt string, option string or text two string not NULL.\r
+\r
+  This is an internal function.\r
+\r
+  @param  MenuOption             The MenuOption to be checked.\r
+\r
+  @retval TRUE                   This Menu Option is printable.\r
+  @retval FALSE                  This Menu Option could not be printable.\r
+\r
+**/\r
+BOOLEAN\r
+PrintableMenu (\r
+  UI_MENU_OPTION   *MenuOption\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_STRING    OptionString;\r
+\r
+  OptionString = NULL;\r
+\r
+  if (MenuOption->Description[0] != '\0') {\r
+    return TRUE;\r
+  }\r
+\r
+  Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if (OptionString != NULL && OptionString[0] != '\0') {\r
+    FreePool (OptionString);\r
+    return TRUE;\r
+  }\r
+\r
+  if ((MenuOption->ThisTag->OpCode->OpCode  == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {\r
+    OptionString   = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);\r
+    ASSERT (OptionString != NULL);\r
+    if (OptionString[0] != '\0'){\r
+      FreePool (OptionString);\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
 /**\r
   Check whether this Menu Option could be highlighted.\r
 \r
@@ -826,7 +942,7 @@ IsSelectable (
   )\r
 {\r
   if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
-      MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+      MenuOption->GrayOut || MenuOption->ReadOnly || !PrintableMenu (MenuOption)) {\r
     return FALSE;\r
   } else {\r
     return TRUE;\r
@@ -841,19 +957,24 @@ IsSelectable (
   @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
   @param  CurrentPosition        Current position.\r
   @param  GapToTop               Gap position to top or bottom.\r
+  @param  FindInForm             Whether find menu in current form or beyond.\r
 \r
   @return The row distance from current MenuOption to next selectable MenuOption.\r
 \r
   @retval -1       Reach the begin of the menu, still can't find the selectable menu.\r
-  @retval Value    Find the selectable menu, maybe the truly selectable, maybe the l\r
-                   last menu showing at current form.\r
+  @retval Value    Find the selectable menu, maybe the truly selectable, maybe the \r
+                   first menu showing beyond current form or last menu showing in \r
+                   current form.\r
+                   The value is the line number between the new selected menu and the\r
+                   current select menu, not include the new selected menu.\r
 \r
 **/\r
 INTN\r
 MoveToNextStatement (\r
   IN     BOOLEAN                   GoUp,\r
   IN OUT LIST_ENTRY                **CurrentPosition,\r
-  IN     UINTN                     GapToTop\r
+  IN     UINTN                     GapToTop,\r
+  IN     BOOLEAN                   FindInForm\r
   )\r
 {\r
   INTN             Distance;\r
@@ -863,6 +984,11 @@ MoveToNextStatement (
 \r
   Distance      = 0;\r
   Pos           = *CurrentPosition;\r
+\r
+  if (Pos == &gMenuOption) {\r
+    return -1;\r
+  }\r
+\r
   PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
 \r
   while (TRUE) {\r
@@ -874,28 +1000,24 @@ MoveToNextStatement (
     if (NextMenuOption->Row == 0) {\r
       UpdateOptionSkipLines (NextMenuOption);\r
     }\r
-    \r
-    if (GoUp && (PreMenuOption != NextMenuOption)) {\r
-      //\r
-      // In this case, still can't find the selectable menu,\r
-      // return the last one in the showing form.\r
-      //\r
-      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
-        NextMenuOption = PreMenuOption;\r
-        break;\r
-      }\r
 \r
-      //\r
-      // Current Position doesn't need to be caculated when go up.\r
-      // Caculate distanct at first when go up\r
-      //      \r
-      Distance += NextMenuOption->Skip;\r
+    if (IsSelectable (NextMenuOption)) {\r
+      break;\r
     }\r
 \r
-    if (IsSelectable (NextMenuOption)) {\r
+    //\r
+    // In this case, still can't find the selectable menu,\r
+    // return the first one beyond the showing form.\r
+    //\r
+    if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+      if (FindInForm) {\r
+        NextMenuOption = PreMenuOption;\r
+      }\r
       break;\r
     }\r
 \r
+    Distance += NextMenuOption->Skip;\r
+\r
     //\r
     // Arrive at begin of the menu list.\r
     //\r
@@ -904,21 +1026,8 @@ MoveToNextStatement (
       break;\r
     }\r
 \r
-    if (!GoUp) {\r
-      //\r
-      // In this case, still can't find the selectable menu,\r
-      // return the last one in the showing form.\r
-      //\r
-      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
-        NextMenuOption = PreMenuOption;\r
-        break;\r
-      }\r
-\r
-      Distance += NextMenuOption->Skip;\r
-    }\r
-\r
-    PreMenuOption = NextMenuOption;\r
     Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+    PreMenuOption = NextMenuOption;\r
   }\r
 \r
   *CurrentPosition = &NextMenuOption->Link;\r
@@ -1312,6 +1421,58 @@ GetQuestionIdInfo (
   return QuestionHeader->QuestionId;\r
 }\r
 \r
+\r
+/**\r
+  Find the top of screen menu base on the current menu.\r
+\r
+  @param  CurPos                 Current input menu.\r
+  @param  Rows                   Totol screen rows.\r
+  @param  SkipValue              SkipValue for this new form.\r
+\r
+  @retval TopOfScreen            Top of screen menu for the new form.\r
+\r
+**/\r
+LIST_ENTRY *\r
+FindTopOfScreenMenu (\r
+  IN  LIST_ENTRY                      *CurPos,\r
+  IN  UINTN                           Rows,\r
+  OUT UINTN                           *SkipValue\r
+  )\r
+{\r
+  LIST_ENTRY        *Link;\r
+  LIST_ENTRY        *TopOfScreen;\r
+  UI_MENU_OPTION    *PreviousMenuOption;\r
+\r
+  Link = CurPos;\r
+  PreviousMenuOption = NULL;\r
+\r
+  while (Link->BackLink != &gMenuOption) {\r
+    Link = Link->BackLink;\r
+    PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+    if (PreviousMenuOption->Row == 0) {\r
+      UpdateOptionSkipLines (PreviousMenuOption);\r
+    }\r
+    if (Rows <= PreviousMenuOption->Skip) {\r
+      break;\r
+    }\r
+    Rows = Rows - PreviousMenuOption->Skip;\r
+  }\r
+\r
+  if (Link->BackLink == &gMenuOption) {\r
+    TopOfScreen = gMenuOption.ForwardLink;\r
+    if (PreviousMenuOption != NULL && Rows < PreviousMenuOption->Skip) {\r
+      *SkipValue = PreviousMenuOption->Skip - Rows;\r
+    } else {\r
+      *SkipValue = 0;\r
+    }\r
+  } else {\r
+    TopOfScreen = Link;\r
+    *SkipValue = PreviousMenuOption->Skip - Rows;\r
+  }\r
+\r
+  return TopOfScreen;\r
+}\r
+\r
 /**\r
   Find the first menu which will be show at the top.\r
 \r
@@ -1326,17 +1487,16 @@ FindTopMenu (
   IN  FORM_DISPLAY_ENGINE_FORM  *FormData,\r
   OUT LIST_ENTRY                **TopOfScreen,\r
   OUT LIST_ENTRY                **HighlightMenu,\r
-  OUT INTN                      *SkipValue\r
+  OUT UINTN                     *SkipValue\r
   )\r
 {\r
-  LIST_ENTRY                      *Link;\r
   LIST_ENTRY                      *NewPos;\r
   UINTN                           TopRow;\r
   UINTN                           BottomRow;\r
-  UINTN                           Index;\r
   UI_MENU_OPTION                  *SavedMenuOption;\r
-  UINTN                           EndRow;\r
+  UINTN                           TmpValue;\r
 \r
+  TmpValue  = 0;\r
   TopRow    = gStatementDimensions.TopRow    + SCROLL_ARROW_HEIGHT;\r
   BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
 \r
@@ -1347,7 +1507,7 @@ FindTopMenu (
     *TopOfScreen   = gMenuOption.ForwardLink;\r
     *HighlightMenu = gMenuOption.ForwardLink;\r
     if (!IsListEmpty (&gMenuOption)) {\r
-      MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow);\r
+      MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);\r
     }\r
     *SkipValue     = 0;\r
     return;\r
@@ -1380,142 +1540,563 @@ FindTopMenu (
   UpdateOptionSkipLines (SavedMenuOption);\r
 \r
   //\r
-  // If highlight opcode is date/time, keep the highlight row info not change.\r
+  // FormRefreshEvent != NULL means this form will auto exit at an interval, display engine \r
+  // will try to keep highlight on the current position after this form exit and re-enter.\r
   //\r
-  if ((SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP || SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) &&\r
-      (gHighligthMenuInfo.QuestionId != 0) && \r
-      (gHighligthMenuInfo.QuestionId == GetQuestionIdInfo(SavedMenuOption->ThisTag->OpCode))) {\r
-    //\r
-    // Still show the highlight menu before exit from display engine.\r
-    //\r
-    EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+  // HiiHandle + QuestionId can find the only one question in the system.\r
+  //\r
+  // If this question has question id, save the question id info to find the question.\r
+  // else save the opcode buffer to find it.\r
+  //\r
+  if (gFormData->FormRefreshEvent != NULL && gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) {\r
+    if (gHighligthMenuInfo.QuestionId != 0) { \r
+      if (gHighligthMenuInfo.QuestionId == GetQuestionIdInfo(SavedMenuOption->ThisTag->OpCode)) {\r
+        BottomRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+        //\r
+        // SkipValue only used for menu at the top of the form.\r
+        // If Highlight menu is not at the top, this value will be update later.\r
+        //\r
+        TmpValue = gHighligthMenuInfo.SkipValue;\r
+      }\r
+    } else if (gHighligthMenuInfo.OpCode != NULL){\r
+      if (!CompareMem (gHighligthMenuInfo.OpCode, SavedMenuOption->ThisTag->OpCode, gHighligthMenuInfo.OpCode->Length)) {\r
+        BottomRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+        //\r
+        // SkipValue only used for menu at the top of the form.\r
+        // If Highlight menu is not at the top, this value will be update later.\r
+        //\r
+        TmpValue = gHighligthMenuInfo.SkipValue;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (SavedMenuOption->Skip >= BottomRow - TopRow) {\r
+    *TopOfScreen = NewPos;\r
   } else {\r
-    EndRow = BottomRow;\r
+    *TopOfScreen = FindTopOfScreenMenu(NewPos, BottomRow - TopRow - SavedMenuOption->Skip, &TmpValue);\r
   }\r
+  AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
+\r
+  *SkipValue   = TmpValue;\r
+}\r
+\r
+/**\r
+  Update highlight menu info.\r
+\r
+  @param  MenuOption               The menu opton which is highlight.\r
+  @param  SkipValue                The skipvalue info for this menu.\r
+                                   SkipValue only used for the menu at the top of the form.\r
+\r
+**/\r
+VOID\r
+UpdateHighlightMenuInfo (\r
+  IN UI_MENU_OPTION            *MenuOption,\r
+  IN UINTN                     SkipValue\r
+  )\r
+{\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
 \r
   //\r
-  // Base on the selected menu will show at the bottome of next page, \r
-  // select the menu show at the top of the next page. \r
+  // This is the current selected statement\r
   //\r
-  Link    = NewPos;\r
-  for (Index = TopRow + SavedMenuOption->Skip; Index <= EndRow; ) {\r
-    Link = Link->BackLink;\r
-    //\r
-    // Already find the first menu in this form, means highlight menu \r
-    // will show in first page of this form.\r
-    //\r
-    if (Link == &gMenuOption) {\r
-      *TopOfScreen   = gMenuOption.ForwardLink;\r
-      *SkipValue     = 0;\r
-      return;\r
-    }\r
-    SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-    UpdateOptionSkipLines (SavedMenuOption);\r
-    Index += SavedMenuOption->Skip;\r
-  }\r
+  Statement = MenuOption->ThisTag;\r
+\r
+  //\r
+  // Get the highlight statement.\r
+  //\r
+  gUserInput->SelectedStatement = Statement;\r
+  gSequence = (UINT16) MenuOption->Sequence;\r
 \r
   //\r
-  // Found the menu which will show at the top of the page.\r
+  // FormRefreshEvent != NULL means this form will auto exit at an interval, display engine \r
+  // will try to keep highlight on the current position after this form exit and re-enter.\r
   //\r
-  if (Link == NewPos) {\r
+  // HiiHandle + QuestionId can find the only one question in the system.\r
+  //\r
+  // If this question has question id, base on the question id info to find the question.\r
+  // else base on the opcode buffer to find it.\r
+  //\r
+  if (gFormData->FormRefreshEvent != NULL) {\r
+    gHighligthMenuInfo.HiiHandle  = gFormData->HiiHandle;\r
+    gHighligthMenuInfo.QuestionId = GetQuestionIdInfo(Statement->OpCode);\r
+\r
     //\r
-    // The menu can show more than one pages, just show the menu at the top of the page.\r
+    // if question id == 0, save the opcode buffer for later use.\r
     //\r
-    *SkipValue    = 0;\r
-    *TopOfScreen  = Link;\r
+    if (gHighligthMenuInfo.QuestionId == 0) {\r
+      if (gHighligthMenuInfo.OpCode != NULL) {\r
+        FreePool (gHighligthMenuInfo.OpCode);\r
+      }\r
+      gHighligthMenuInfo.OpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);\r
+      ASSERT (gHighligthMenuInfo.OpCode != NULL);\r
+    }\r
+    gHighligthMenuInfo.DisplayRow = (UINT16) MenuOption->Row;\r
+    gHighligthMenuInfo.SkipValue  = (UINT16) SkipValue;\r
   } else {\r
-    //\r
-    // Check whether need to skip some line for menu shows at the top of the page.\r
-    //\r
-    *SkipValue = Index - EndRow;\r
-    if (*SkipValue > 0 && *SkipValue < (INTN) SavedMenuOption->Skip) {\r
-      *TopOfScreen     = Link;\r
-    } else {\r
-      *SkipValue       = 0;\r
-      *TopOfScreen     = Link->ForwardLink;\r
+    gHighligthMenuInfo.HiiHandle  = NULL;\r
+    gHighligthMenuInfo.QuestionId = 0;\r
+    if (gHighligthMenuInfo.OpCode != NULL) {\r
+      FreePool (gHighligthMenuInfo.OpCode);\r
+      gHighligthMenuInfo.OpCode = NULL;\r
     }\r
+    gHighligthMenuInfo.DisplayRow = 0;\r
+    gHighligthMenuInfo.SkipValue  = 0;\r
   }\r
+\r
+  RefreshKeyHelp(gFormData, Statement, FALSE);\r
 }\r
 \r
 /**\r
-  Display menu and wait for user to select one menu option, then return it.\r
-  If AutoBoot is enabled, then if user doesn't select any option,\r
-  after period of time, it will automatically return the first menu option.\r
-\r
-  @param  FormData               The current form data info.\r
+  Update attribut for this menu.\r
 \r
-  @retval EFI_SUCESSS            Process the user selection success.\r
-  @retval EFI_NOT_FOUND          Process option string for orderedlist/Oneof fail.\r
+  @param  MenuOption               The menu opton which this attribut used to.\r
+  @param  Highlight                Whether this menu will be highlight.\r
 \r
 **/\r
-EFI_STATUS\r
-UiDisplayMenu (\r
-  IN  FORM_DISPLAY_ENGINE_FORM  *FormData\r
+VOID\r
+SetDisplayAttribute (\r
+  IN UI_MENU_OPTION                  *MenuOption,\r
+  IN BOOLEAN                         Highlight\r
   )\r
 {\r
-  INTN                            SkipValue;\r
-  INTN                            Difference;\r
-  UINTN                           DistanceValue;\r
-  UINTN                           Row;\r
-  UINTN                           Col;\r
-  UINTN                           TempRightCol;\r
-  UINTN                           Temp;\r
-  UINTN                           Temp2;\r
-  UINTN                           Temp3;\r
-  UINTN                           TopRow;\r
-  UINTN                           BottomRow;\r
-  UINTN                           OriginalRow;\r
-  UINTN                           Index;\r
-  UINT16                          Width;\r
-  CHAR16                          *StringPtr;\r
-  CHAR16                          *OptionString;\r
-  CHAR16                          *OutputString;\r
-  CHAR16                          *HelpString;\r
-  CHAR16                          *HelpHeaderString;\r
-  CHAR16                          *HelpBottomString;\r
-  BOOLEAN                         NewLine;\r
-  BOOLEAN                         Repaint;\r
-  BOOLEAN                         UpArrow;\r
-  BOOLEAN                         DownArrow;\r
-  EFI_STATUS                      Status;\r
-  EFI_INPUT_KEY                   Key;\r
-  LIST_ENTRY                      *Link;\r
-  LIST_ENTRY                      *NewPos;\r
-  LIST_ENTRY                      *TopOfScreen;\r
-  LIST_ENTRY                      *SavedListEntry;\r
-  UI_MENU_OPTION                  *MenuOption;\r
-  UI_MENU_OPTION                  *NextMenuOption;\r
-  UI_MENU_OPTION                  *SavedMenuOption;\r
-  UI_MENU_OPTION                  *PreviousMenuOption;\r
-  UI_CONTROL_FLAG                 ControlFlag;\r
-  UI_SCREEN_OPERATION             ScreenOperation;\r
-  UINT16                          DefaultId;\r
   FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
-  UINTN                           ModalSkipColumn;\r
-  BROWSER_HOT_KEY                 *HotKey;\r
-  UINTN                           HelpPageIndex;\r
-  UINTN                           HelpPageCount;\r
-  UINTN                           RowCount;\r
-  UINTN                           HelpLine;\r
-  UINTN                           HelpHeaderLine;\r
-  UINTN                           HelpBottomLine;\r
-  BOOLEAN                         MultiHelpPage;\r
-  UINT16                          GlyphWidth;\r
-  UINT16                          EachLineWidth;\r
-  UINT16                          HeaderLineWidth;\r
-  UINT16                          BottomLineWidth;\r
-  EFI_STRING_ID                   HelpInfo;\r
-  UI_EVENT_TYPE                   EventType;\r
-  FORM_DISPLAY_ENGINE_STATEMENT   *InitialHighlight;\r
+  \r
+  Statement = MenuOption->ThisTag;\r
 \r
-  EventType           = UIEventNone;\r
-  Status              = EFI_SUCCESS;\r
-  HelpString          = NULL;\r
-  HelpHeaderString    = NULL;\r
-  HelpBottomString    = NULL;\r
-  OptionString        = NULL;\r
-  ScreenOperation     = UiNoOperation;\r
-  NewLine             = TRUE;\r
+  if (Highlight) {\r
+    gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
+    return;\r
+  }\r
+\r
+  if (MenuOption->GrayOut) {\r
+    gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
+  } else {\r
+    if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Print string for this menu option.\r
+\r
+  @param  MenuOption               The menu opton which this attribut used to.\r
+  @param  Col                      The column that this string will be print at.\r
+  @param  Row                      The row that this string will be print at.\r
+  @param  String                   The string which need to print.\r
+  @param  Width                    The width need to print, if string is less than the\r
+                                   width, the block space will be used.\r
+  @param  Highlight                Whether this menu will be highlight.\r
+\r
+**/\r
+VOID\r
+DisplayMenuString (\r
+  IN UI_MENU_OPTION         *MenuOption,\r
+  IN UINTN                  Col,\r
+  IN UINTN                  Row,\r
+  IN CHAR16                 *String,\r
+  IN UINTN                  Width,\r
+  IN BOOLEAN                Highlight\r
+  )\r
+{\r
+  UINTN            Length;\r
+\r
+  //\r
+  // Print string with normal color.\r
+  //\r
+  if (!Highlight) {\r
+    PrintStringAtWithWidth (Col, Row, String, Width);\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Print the highlight menu string.\r
+  // First print the highlight string.\r
+  // \r
+  SetDisplayAttribute(MenuOption, TRUE);\r
+  Length = PrintStringAt (Col, Row, String);\r
+\r
+  //\r
+  // Second, clean the empty after the string.\r
+  //\r
+  SetDisplayAttribute(MenuOption, FALSE);\r
+  PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);\r
+}\r
+\r
+/**\r
+  Check whether this menu can has option string.\r
+\r
+  @param  MenuOption               The menu opton which this attribut used to.\r
+\r
+  @retval TRUE                     This menu option can have option string.\r
+  @retval FALSE                    This menu option can't have option string.\r
+\r
+**/\r
+BOOLEAN \r
+HasOptionString (\r
+  IN UI_MENU_OPTION                  *MenuOption\r
+  )\r
+{\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
+  CHAR16                          *String;\r
+  UINTN                           Size;\r
+  EFI_IFR_TEXT                    *TestOp;\r
+\r
+  Size = 0;\r
+  Statement = MenuOption->ThisTag;\r
+\r
+  //\r
+  // See if the second text parameter is really NULL\r
+  //\r
+  if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
+    TestOp = (EFI_IFR_TEXT *) Statement->OpCode;\r
+    if (TestOp->TextTwo != 0) {\r
+      String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);\r
+      Size   = StrLen (String);\r
+      FreePool (String);\r
+    }\r
+  }\r
+\r
+  if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
+    (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||\r
+    (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||\r
+    (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||\r
+    (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||\r
+    //\r
+    // Allow a wide display if text op-code and no secondary text op-code\r
+    //\r
+    ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))\r
+    ) {\r
+\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Print string for this menu option.\r
+\r
+  @param  MenuOption               The menu opton which this attribut used to.\r
+  @param  SkipWidth                The skip width between the left to the start of the prompt.\r
+  @param  BeginCol                 The begin column for one menu.\r
+  @param  SkipLine                 The skip line for this menu. \r
+  @param  BottomRow                The bottom row for this form.\r
+  @param  Highlight                Whether this menu will be highlight.\r
+  @param  UpdateCol                Whether need to update the column info for Date/Time.\r
+\r
+  @retval EFI_SUCESSS              Process the user selection success.\r
+\r
+**/\r
+EFI_STATUS\r
+DisplayOneMenu (\r
+  IN UI_MENU_OPTION                  *MenuOption,\r
+  IN UINTN                           SkipWidth,\r
+  IN UINTN                           BeginCol,\r
+  IN UINTN                           SkipLine,\r
+  IN UINTN                           BottomRow,\r
+  IN BOOLEAN                         Highlight,\r
+  IN BOOLEAN                         UpdateCol\r
+  )\r
+{\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
+  UINTN                           Index;\r
+  UINT16                          Width;\r
+  UINT16                          PromptWidth;\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *OptionString;\r
+  CHAR16                          *OutputString;\r
+  UINT16                          GlyphWidth;\r
+  UINTN                           Temp;\r
+  UINTN                           Temp2;\r
+  UINTN                           Temp3;\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Row;\r
+  UINTN                           Col;\r
+  UINTN                           PromptLineNum;\r
+  UINTN                           OptionLineNum;\r
+  CHAR16                          AdjustValue;\r
+  UINTN                           MaxRow;\r
+\r
+  Statement = MenuOption->ThisTag;\r
+  Temp      = SkipLine;\r
+  Temp2     = SkipLine;\r
+  Temp3     = SkipLine;\r
+  AdjustValue   = 0;\r
+  PromptLineNum = 0;\r
+  OptionLineNum = 0;\r
+  MaxRow        = 0;\r
+\r
+  //\r
+  // Set default color.\r
+  //\r
+  SetDisplayAttribute (MenuOption, FALSE);\r
+\r
+  //\r
+  // 1. Paint the option string.\r
+  //\r
+  Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (OptionString != NULL) {\r
+    if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+      //\r
+      // Adjust option string for date/time opcode.\r
+      //\r
+      ProcessStringForDateTime(MenuOption, OptionString, UpdateCol);\r
+    }\r
+  \r
+    Width       = (UINT16) gOptionBlockWidth - 1;\r
+    Row         = MenuOption->Row;\r
+    GlyphWidth  = 1;\r
+    OptionLineNum = 0;\r
+  \r
+    for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+      if (((Temp2 == 0)) && (Row <= BottomRow)) {\r
+        if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+          //\r
+          // For date/time question, it has three menu options for this qustion.\r
+          // The first/second menu options with the skip value is 0. the last one\r
+          // with skip value is 1.\r
+          //\r
+          if (MenuOption->Skip != 0) {\r
+            //\r
+            // For date/ time, print the last past (year for date and second for time)\r
+            // - 7 means skip [##/##/ for date and [##:##: for time.\r
+            //\r
+            DisplayMenuString (MenuOption,MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);\r
+          } else {\r
+            //\r
+            // For date/ time, print the first and second past (year for date and second for time)\r
+            // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string, \r
+            // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.\r
+            DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString) - 1, Highlight);\r
+          }\r
+        } else {\r
+          DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);\r
+        }\r
+        OptionLineNum++;\r
+      }\r
+      \r
+      //\r
+      // If there is more string to process print on the next row and increment the Skip value\r
+      //\r
+      if (StrLen (&OptionString[Index]) != 0) {\r
+        if (Temp2 == 0) {\r
+          Row++;\r
+          //\r
+          // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+          // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+          // some testing to ensure we are keeping this in-sync.\r
+          //\r
+          // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+          //\r
+          if ((Row - MenuOption->Row) >= MenuOption->Skip) {\r
+            MenuOption->Skip++;\r
+          }\r
+        }\r
+      }\r
+  \r
+      FreePool (OutputString);\r
+      if (Temp2 != 0) {\r
+        Temp2--;\r
+      }\r
+    }\r
+  \r
+    Highlight = FALSE;\r
+\r
+    FreePool (OptionString);\r
+  }\r
+\r
+  //\r
+  // 2. Paint the description.\r
+  //\r
+  PromptWidth   = GetWidth (MenuOption, &AdjustValue);\r
+  Row           = MenuOption->Row;\r
+  GlyphWidth    = 1;\r
+  PromptLineNum = 0;\r
+\r
+  if (MenuOption->Description == NULL || MenuOption->Description[0] == '\0') {\r
+    PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);\r
+    PromptLineNum++;\r
+  } else {\r
+    for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) {      \r
+      if ((Temp == 0) && (Row <= BottomRow)) { \r
+        //\r
+        // 1.Clean the start LEFT_SKIPPED_COLUMNS \r
+        //\r
+        PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);\r
+        \r
+        if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
+          //\r
+          // Print Arrow for Goto button.\r
+          //\r
+          PrintCharAt (\r
+            MenuOption->Col - 2,\r
+            Row,\r
+            GEOMETRICSHAPE_RIGHT_TRIANGLE\r
+            );\r
+        }\r
+        DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);\r
+        PromptLineNum ++;\r
+      }\r
+      //\r
+      // If there is more string to process print on the next row and increment the Skip value\r
+      //\r
+      if (StrLen (&MenuOption->Description[Index]) != 0) {\r
+        if (Temp == 0) {\r
+          Row++;\r
+        }\r
+      }\r
+\r
+      FreePool (OutputString);\r
+      if (Temp != 0) {\r
+        Temp--;\r
+      }\r
+    }\r
+\r
+    Highlight = FALSE;\r
+  }\r
+\r
+\r
+  //\r
+  // 3. If this is a text op with secondary text information\r
+  //\r
+  if ((Statement->OpCode->OpCode  == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) {\r
+    StringPtr   = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle);\r
+  \r
+    Width       = (UINT16) gOptionBlockWidth - 1;\r
+    Row         = MenuOption->Row;\r
+    GlyphWidth  = 1;\r
+    OptionLineNum = 0;\r
+\r
+    for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { \r
+      if ((Temp3 == 0) && (Row <= BottomRow)) {\r
+        DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);\r
+        OptionLineNum++;\r
+      }\r
+      //\r
+      // If there is more string to process print on the next row and increment the Skip value\r
+      //\r
+      if (StrLen (&StringPtr[Index]) != 0) {\r
+        if (Temp3 == 0) {\r
+          Row++;\r
+          //\r
+          // If the rows for text two is greater than or equal to the skip value, increase the skip value\r
+          //\r
+          if ((Row - MenuOption->Row) >= MenuOption->Skip) {\r
+            MenuOption->Skip++;\r
+          }\r
+        }\r
+      }\r
+  \r
+      FreePool (OutputString);\r
+      if (Temp3 != 0) {\r
+        Temp3--;\r
+      }\r
+    }\r
+\r
+    FreePool (StringPtr);\r
+  }\r
+\r
+  //\r
+  // 4.Line number for Option string and prompt string are not equal.\r
+  //  Clean the column whose line number is less.\r
+  //\r
+  if (HasOptionString(MenuOption) && (OptionLineNum != PromptLineNum)) {\r
+    Col    =  OptionLineNum < PromptLineNum ? MenuOption->OptCol : BeginCol;\r
+    Row    = (OptionLineNum < PromptLineNum ? OptionLineNum : PromptLineNum) + MenuOption->Row;\r
+    Width  = (UINT16) (OptionLineNum < PromptLineNum ? gOptionBlockWidth : PromptWidth + AdjustValue + SkipWidth);\r
+    MaxRow = (OptionLineNum < PromptLineNum ? PromptLineNum : OptionLineNum) + MenuOption->Row - 1;\r
+    \r
+    while (Row <= MaxRow) {\r
+      DisplayMenuString (MenuOption, Col, Row++, L"", Width, FALSE);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Display menu and wait for user to select one menu option, then return it.\r
+  If AutoBoot is enabled, then if user doesn't select any option,\r
+  after period of time, it will automatically return the first menu option.\r
+\r
+  @param  FormData               The current form data info.\r
+\r
+  @retval EFI_SUCESSS            Process the user selection success.\r
+  @retval EFI_NOT_FOUND          Process option string for orderedlist/Oneof fail.\r
+\r
+**/\r
+EFI_STATUS\r
+UiDisplayMenu (\r
+  IN  FORM_DISPLAY_ENGINE_FORM  *FormData\r
+  )\r
+{\r
+  UINTN                           SkipValue;\r
+  INTN                            Difference;\r
+  UINTN                           DistanceValue;\r
+  UINTN                           Row;\r
+  UINTN                           Col;\r
+  UINTN                           Temp;\r
+  UINTN                           Temp2;\r
+  UINTN                           TopRow;\r
+  UINTN                           BottomRow;\r
+  UINTN                           Index;\r
+  UINT16                          Width;\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *OptionString;\r
+  CHAR16                          *OutputString;\r
+  CHAR16                          *HelpString;\r
+  CHAR16                          *HelpHeaderString;\r
+  CHAR16                          *HelpBottomString;\r
+  BOOLEAN                         NewLine;\r
+  BOOLEAN                         Repaint;\r
+  BOOLEAN                         UpArrow;\r
+  BOOLEAN                         DownArrow;\r
+  EFI_STATUS                      Status;\r
+  EFI_INPUT_KEY                   Key;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NewPos;\r
+  LIST_ENTRY                      *TopOfScreen;\r
+  LIST_ENTRY                      *SavedListEntry;\r
+  UI_MENU_OPTION                  *MenuOption;\r
+  UI_MENU_OPTION                  *NextMenuOption;\r
+  UI_MENU_OPTION                  *SavedMenuOption;\r
+  UI_MENU_OPTION                  *PreviousMenuOption;\r
+  UI_CONTROL_FLAG                 ControlFlag;\r
+  UI_SCREEN_OPERATION             ScreenOperation;\r
+  UINT16                          DefaultId;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
+  BROWSER_HOT_KEY                 *HotKey;\r
+  UINTN                           HelpPageIndex;\r
+  UINTN                           HelpPageCount;\r
+  UINTN                           RowCount;\r
+  UINTN                           HelpLine;\r
+  UINTN                           HelpHeaderLine;\r
+  UINTN                           HelpBottomLine;\r
+  BOOLEAN                         MultiHelpPage;\r
+  UINT16                          EachLineWidth;\r
+  UINT16                          HeaderLineWidth;\r
+  UINT16                          BottomLineWidth;\r
+  EFI_STRING_ID                   HelpInfo;\r
+  UI_EVENT_TYPE                   EventType;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *InitialHighlight;\r
+  BOOLEAN                         SkipHighLight;\r
+\r
+  EventType           = UIEventNone;\r
+  Status              = EFI_SUCCESS;\r
+  HelpString          = NULL;\r
+  HelpHeaderString    = NULL;\r
+  HelpBottomString    = NULL;\r
+  OptionString        = NULL;\r
+  ScreenOperation     = UiNoOperation;\r
+  NewLine             = TRUE;\r
   DefaultId           = 0;\r
   HelpPageCount       = 0;\r
   HelpLine            = 0;\r
@@ -1531,6 +2112,7 @@ UiDisplayMenu (
   UpArrow             = FALSE;\r
   DownArrow           = FALSE;\r
   SkipValue           = 0;\r
+  SkipHighLight       = FALSE;\r
 \r
   NextMenuOption      = NULL;\r
   PreviousMenuOption  = NULL;\r
@@ -1538,21 +2120,27 @@ UiDisplayMenu (
   HotKey              = NULL;\r
   Repaint             = TRUE;\r
   MenuOption          = NULL;\r
-  ModalSkipColumn     = (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;\r
+  gModalSkipColumn    = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;\r
   InitialHighlight    = gFormData->HighLightedStatement;\r
 \r
   ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
 \r
-  gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3);\r
-  gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);\r
-  gHelpBlockWidth   = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);\r
+  //\r
+  //  Left                                              right\r
+  //   |<-.->|<-.........->|<- .........->|<-...........->|\r
+  //     Skip    Prompt         Option         Help \r
+  //\r
+  Width             = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3);\r
+  gOptionBlockWidth = Width + 1; \r
+  gHelpBlockWidth   = (CHAR16) (Width - LEFT_SKIPPED_COLUMNS);\r
+  gPromptBlockWidth = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * Width - 1);\r
 \r
   TopRow    = gStatementDimensions.TopRow    + SCROLL_ARROW_HEIGHT;\r
   BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;\r
 \r
   Row = TopRow;\r
   if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
-    Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
+    Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;\r
   } else {\r
     Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
   }\r
@@ -1565,30 +2153,21 @@ UiDisplayMenu (
   while (TRUE) {\r
     switch (ControlFlag) {\r
     case CfInitialization:\r
-      if (IsListEmpty (&gMenuOption)) {\r
-        \r
-        if ((FormData->Attribute & HII_DISPLAY_MODAL) == 0) {\r
-          //\r
-          // Clear Statement range.\r
-          //\r
-          ClearLines (\r
-            gStatementDimensions.LeftColumn,\r
-            gStatementDimensions.RightColumn,\r
-            TopRow - SCROLL_ARROW_HEIGHT,\r
-            BottomRow + SCROLL_ARROW_HEIGHT,\r
-            GetFieldTextColor ()\r
-            );\r
-            \r
-          //\r
-          // Clear Key Range\r
-          //\r
-          RefreshKeyHelp (gFormData, NULL, FALSE);\r
-        }\r
+      if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) || \r
+          (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))) {\r
+        //\r
+        // Clear Statement range if different formset is painted.\r
+        //\r
+        ClearLines (\r
+          gStatementDimensions.LeftColumn,\r
+          gStatementDimensions.RightColumn,\r
+          TopRow - SCROLL_ARROW_HEIGHT,\r
+          BottomRow + SCROLL_ARROW_HEIGHT,\r
+          GetFieldTextColor ()\r
+          );\r
 \r
-        ControlFlag = CfReadKey;\r
-      } else {\r
-        ControlFlag = CfRepaint;\r
       }\r
+      ControlFlag = CfRepaint;\r
       break;\r
 \r
     case CfRepaint:\r
@@ -1602,47 +2181,28 @@ UiDisplayMenu (
         UpArrow         = FALSE;\r
         Row             = TopRow;\r
 \r
-        Temp            = (UINTN) SkipValue;\r
-        Temp2           = (UINTN) SkipValue;\r
-        Temp3           = (UINTN) SkipValue;\r
-\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+        \r
         //\r
-        // 1. Clear the screen.\r
+        // 1. Check whether need to print the arrow up.\r
         //\r
+        if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
+          UpArrow = TRUE;\r
+        }\r
+\r
         if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
-          ClearLines (\r
-            gStatementDimensions.LeftColumn + ModalSkipColumn,\r
-            gStatementDimensions.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
-            TopRow - SCROLL_ARROW_HEIGHT,\r
-            BottomRow + SCROLL_ARROW_HEIGHT,\r
-            GetFieldTextColor ()\r
-            );\r
+          PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);\r
         } else {\r
-          TempRightCol = gStatementDimensions.RightColumn;\r
-          if (!mStatementLayoutIsChanged) {\r
-            TempRightCol = gStatementDimensions.RightColumn - gHelpBlockWidth;\r
-          }\r
-          ClearLines (\r
-            gStatementDimensions.LeftColumn,\r
-            gStatementDimensions.RightColumn,\r
+          PrintStringAtWithWidth(gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\r
+        }\r
+        if (UpArrow) {\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
+          PrintCharAt (\r
+            gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
             TopRow - SCROLL_ARROW_HEIGHT,\r
-            TopRow - 1,\r
-            GetFieldTextColor ()\r
-            );\r
-          ClearLines (\r
-            gStatementDimensions.LeftColumn,\r
-            TempRightCol,\r
-            TopRow,\r
-            BottomRow,\r
-            GetFieldTextColor ()\r
-            );\r
-          ClearLines (\r
-            gStatementDimensions.LeftColumn,\r
-            gStatementDimensions.RightColumn,\r
-            BottomRow + 1,\r
-            BottomRow + SCROLL_ARROW_HEIGHT,\r
-            GetFieldTextColor ()\r
+            ARROW_UP\r
             );\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
         }\r
 \r
         //\r
@@ -1653,169 +2213,46 @@ UiDisplayMenu (
           MenuOption->Row     = Row;\r
           MenuOption->Col     = Col;\r
           if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
-            MenuOption->OptCol  = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn + ModalSkipColumn;\r
+            MenuOption->OptCol  = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth + gModalSkipColumn;\r
           } else {\r
-            MenuOption->OptCol  = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn;\r
+            MenuOption->OptCol  = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;\r
           }\r
 \r
-          Statement = MenuOption->ThisTag;\r
           if (MenuOption->NestInStatement) {\r
             MenuOption->Col += SUBTITLE_INDENT;\r
           }\r
 \r
-          if (MenuOption->GrayOut) {\r
-            gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
-          } else {\r
-            if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
-              gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
-            }\r
-          }\r
-\r
-          Width       = GetWidth (Statement);\r
-          OriginalRow = Row;\r
-          GlyphWidth  = 1;\r
-\r
-          if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
-            //\r
-            // Print Arrow for Goto button.\r
-            //\r
-            PrintCharAt (\r
-              MenuOption->Col - 2,\r
-              Row,\r
-              GEOMETRICSHAPE_RIGHT_TRIANGLE\r
-              );\r
-          }\r
-\r
           //\r
-          // 2.1. Paint the description.\r
+          // Save the highlight menu, will be used in CfRefreshHighLight case.\r
           //\r
-          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-            //\r
-            // Temp means need to skip how many lines from the start.\r
-            //\r
-            if ((Temp == 0) && (Row <= BottomRow)) {\r
-              PrintStringAt (MenuOption->Col, Row, OutputString);\r
-            }\r
-            //\r
-            // If there is more string to process print on the next row and increment the Skip value\r
-            //\r
-            if (StrLen (&MenuOption->Description[Index]) != 0) {\r
-              if (Temp == 0) {\r
-                Row++;\r
-              }\r
-            }\r
-\r
-            FreePool (OutputString);\r
-            if (Temp != 0) {\r
-              Temp--;\r
-            }\r
+          if (Link == NewPos) {\r
+            SavedMenuOption = MenuOption;\r
+            SkipHighLight   = TRUE;\r
           }\r
 \r
-          Temp  = 0;\r
-          Row   = OriginalRow;\r
+          if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+            Status = DisplayOneMenu (MenuOption, \r
+                            MenuOption->Col - gStatementDimensions.LeftColumn,\r
+                            gStatementDimensions.LeftColumn + gModalSkipColumn, \r
+                            Link == TopOfScreen ? SkipValue : 0, \r
+                            BottomRow,\r
+                            (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),\r
+                            TRUE\r
+                            );\r
+          } else {\r
+            Status = DisplayOneMenu (MenuOption, \r
+                            MenuOption->Col - gStatementDimensions.LeftColumn,\r
+                            gStatementDimensions.LeftColumn, \r
+                            Link == TopOfScreen ? SkipValue : 0, \r
+                            BottomRow,\r
+                            (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),\r
+                            TRUE\r
+                            );\r
+          }\r
 \r
-          //\r
-          // 2.2. Paint the option string.\r
-          //\r
-          Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
-          //\r
-          // If Error occur, question value update in ProcessOptions.\r
-          // Exit current FormDisplay with new question value.\r
-          //\r
           if (EFI_ERROR (Status)) {\r
             return Status;\r
           }\r
-\r
-          if (OptionString != NULL) {\r
-            if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
-              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
-            }\r
-\r
-            Width       = (UINT16) gOptionBlockWidth;\r
-            OriginalRow = Row;\r
-            GlyphWidth  = 1;\r
-\r
-            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-              if ((Temp2 == 0) && (Row <= BottomRow)) {\r
-                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
-              }\r
-              //\r
-              // If there is more string to process print on the next row and increment the Skip value\r
-              //\r
-              if (StrLen (&OptionString[Index]) != 0) {\r
-                if (Temp2 == 0) {\r
-                  Row++;\r
-                  //\r
-                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
-                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
-                  // some testing to ensure we are keeping this in-sync.\r
-                  //\r
-                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
-                  //\r
-                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
-                    MenuOption->Skip++;\r
-                  }\r
-                }\r
-              }\r
-\r
-              FreePool (OutputString);\r
-              if (Temp2 != 0) {\r
-                Temp2--;\r
-              }\r
-            }\r
-\r
-            Row   = OriginalRow;\r
-\r
-            FreePool (OptionString);\r
-          }\r
-          Temp2 = 0;\r
-\r
-          //\r
-          // If this is a text op with secondary text information\r
-          //\r
-          if ((Statement->OpCode->OpCode  == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) {\r
-            StringPtr   = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle);\r
-\r
-            Width       = (UINT16) gOptionBlockWidth;\r
-            OriginalRow = Row;\r
-            GlyphWidth = 1;\r
-\r
-            for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-              if ((Temp3 == 0) && (Row <= BottomRow)) {\r
-                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
-              }\r
-              //\r
-              // If there is more string to process print on the next row and increment the Skip value\r
-              //\r
-              if (StrLen (&StringPtr[Index]) != 0) {\r
-                if (Temp3 == 0) {\r
-                  Row++;\r
-                  //\r
-                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
-                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
-                  // some testing to ensure we are keeping this in-sync.\r
-                  //\r
-                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
-                  //\r
-                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
-                    MenuOption->Skip++;\r
-                  }\r
-                }\r
-              }\r
-\r
-              FreePool (OutputString);\r
-              if (Temp3 != 0) {\r
-                Temp3--;\r
-              }\r
-            }\r
-\r
-            Row = OriginalRow;\r
-            FreePool (StringPtr);\r
-          }\r
-          Temp3 = 0;\r
-\r
-          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
-\r
           //\r
           // 3. Update the row info which will be used by next menu.\r
           //\r
@@ -1835,20 +2272,25 @@ UiDisplayMenu (
           }\r
         }\r
 \r
-        if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
-          UpArrow = TRUE;\r
+        //\r
+        // 3. Menus in this form may not cover all form, clean the remain field.\r
+        //\r
+        while (Row <= BottomRow) {\r
+          if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+            PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);\r
+          } else {\r
+            PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);\r
+          }\r
         }\r
 \r
-        if (UpArrow) {\r
-          gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
-          PrintCharAt (\r
-            gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
-            TopRow - SCROLL_ARROW_HEIGHT,\r
-            ARROW_UP\r
-            );\r
-          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+        //\r
+        // 4. Print the down arrow row.\r
+        //\r
+        if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+          PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 *  + gModalSkipColumn);\r
+        } else {\r
+          PrintStringAtWithWidth(gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\r
         }\r
-\r
         if (DownArrow) {\r
           gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
           PrintCharAt (\r
@@ -1872,6 +2314,21 @@ UiDisplayMenu (
       //\r
       ControlFlag = CfUpdateHelpString;\r
 \r
+      if (SkipHighLight) {\r
+        MenuOption    = SavedMenuOption;\r
+        SkipHighLight = FALSE;\r
+        UpdateHighlightMenuInfo (MenuOption, TopOfScreen == &MenuOption->Link ? SkipValue : 0);\r
+        break;\r
+      }\r
+\r
+      if (IsListEmpty (&gMenuOption)) {\r
+        //\r
+        // No menu option, just update the hotkey filed.\r
+        //\r
+        RefreshKeyHelp(gFormData, NULL, FALSE);\r
+        break;\r
+      }\r
+\r
       if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {\r
         Temp = SkipValue;\r
       } else {\r
@@ -1886,79 +2343,16 @@ UiDisplayMenu (
       if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
         if (MenuOption != NULL) {\r
           //\r
-          // Remove highlight on last Menu Option\r
+          // Remove the old highlight menu.\r
           //\r
-          gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
-          ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
-          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
-          if (OptionString != NULL) {\r
-            if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
-                (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)\r
-               ) {\r
-              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
-            }\r
-\r
-            Width               = (UINT16) gOptionBlockWidth;\r
-            OriginalRow         = MenuOption->Row;\r
-            GlyphWidth          = 1;\r
-\r
-            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-              if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {\r
-                PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
-              }\r
-              //\r
-              // If there is more string to process print on the next row and increment the Skip value\r
-              //\r
-              if (StrLen (&OptionString[Index]) != 0) {\r
-                if (Temp == 0) {\r
-                  MenuOption->Row++;\r
-                }\r
-              }\r
-\r
-              FreePool (OutputString);\r
-              if (Temp != 0) {\r
-                Temp--;\r
-              }\r
-            }\r
-\r
-            MenuOption->Row = OriginalRow;\r
-\r
-            FreePool (OptionString);\r
-          } else {\r
-            if (NewLine) {\r
-              if (MenuOption->GrayOut) {\r
-                gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
-              } else if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
-                gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
-              }\r
-\r
-              OriginalRow = MenuOption->Row;\r
-              Width       = GetWidth (MenuOption->ThisTag);\r
-              GlyphWidth  = 1;\r
-\r
-              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-                if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {\r
-                  PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
-                }\r
-                //\r
-                // If there is more string to process print on the next row and increment the Skip value\r
-                //\r
-                if (StrLen (&MenuOption->Description[Index]) != 0) {\r
-                  if (Temp == 0) {\r
-                    MenuOption->Row++;\r
-                  }\r
-                }\r
-\r
-                FreePool (OutputString);\r
-                if (Temp != 0) {\r
-                  Temp--;\r
-                }\r
-              }\r
-\r
-              MenuOption->Row = OriginalRow;\r
-              gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
-            }\r
-          }\r
+          Status = DisplayOneMenu (MenuOption, \r
+                          MenuOption->Col - gStatementDimensions.LeftColumn,\r
+                          gStatementDimensions.LeftColumn, \r
+                          Temp, \r
+                          BottomRow,\r
+                          FALSE,\r
+                          FALSE\r
+                          );\r
         }\r
 \r
         //\r
@@ -1967,103 +2361,20 @@ UiDisplayMenu (
         MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
         Statement = MenuOption->ThisTag;\r
 \r
-        //\r
-        // Get the highlight statement.\r
-        //\r
-        gUserInput->SelectedStatement = Statement;\r
-        gSequence = (UINT16) MenuOption->Sequence;\r
-\r
-        //\r
-        // Record highlight row info for date/time opcode.\r
-        //\r
-        if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
-          gHighligthMenuInfo.QuestionId = GetQuestionIdInfo(Statement->OpCode);\r
-          gHighligthMenuInfo.DisplayRow = (UINT16) MenuOption->Row;\r
-        } else {\r
-          gHighligthMenuInfo.QuestionId = 0;\r
-          gHighligthMenuInfo.DisplayRow = 0;\r
-        }\r
+        UpdateHighlightMenuInfo (MenuOption, Temp2);\r
 \r
         if (!IsSelectable (MenuOption)) {\r
-          RefreshKeyHelp(gFormData, Statement, FALSE);\r
           break;\r
         }\r
 \r
-        //\r
-        // Set reverse attribute\r
-        //\r
-        gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
-        gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
-\r
-        ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
-        if (OptionString != NULL) {\r
-          if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
-            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
-          }\r
-          Width               = (UINT16) gOptionBlockWidth;\r
-\r
-          OriginalRow         = MenuOption->Row;\r
-          GlyphWidth          = 1;\r
-\r
-          for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-            if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {\r
-              PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
-            }\r
-            //\r
-            // If there is more string to process print on the next row and increment the Skip value\r
-            //\r
-            if (StrLen (&OptionString[Index]) != 0) {\r
-              if (Temp2 == 0) {\r
-              MenuOption->Row++;\r
-              }\r
-            }\r
-\r
-            FreePool (OutputString);\r
-            if (Temp2 != 0) {\r
-              Temp2--;\r
-            }\r
-          }\r
-\r
-          MenuOption->Row = OriginalRow;\r
-\r
-          FreePool (OptionString);\r
-        } else {\r
-          if (NewLine) {\r
-            OriginalRow = MenuOption->Row;\r
-\r
-            Width       = GetWidth (Statement);\r
-            GlyphWidth          = 1;\r
-\r
-            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
-              if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {\r
-                PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
-              }\r
-              //\r
-              // If there is more string to process print on the next row and increment the Skip value\r
-              //\r
-              if (StrLen (&MenuOption->Description[Index]) != 0) {\r
-                if (Temp2 == 0) {\r
-                  MenuOption->Row++;\r
-                }\r
-              }\r
-\r
-              FreePool (OutputString);\r
-              if (Temp2 != 0) {\r
-                Temp2--;\r
-              }\r
-            }\r
-\r
-            MenuOption->Row = OriginalRow;\r
-\r
-          }\r
-        }\r
-\r
-        RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE);\r
-\r
-        //\r
-        // Clear reverse attribute\r
-        //\r
-        gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+        Status = DisplayOneMenu (MenuOption, \r
+                        MenuOption->Col - gStatementDimensions.LeftColumn,\r
+                        gStatementDimensions.LeftColumn, \r
+                        Temp2, \r
+                        BottomRow,\r
+                        TRUE,\r
+                        FALSE\r
+                        );\r
       }\r
       break;\r
 \r
@@ -2073,16 +2384,27 @@ UiDisplayMenu (
         break;\r
       }\r
 \r
+      //\r
+      // NewLine means only update highlight menu (remove old highlight and highlith\r
+      // the new one), not need to full repain the form.\r
+      //\r
       if (Repaint || NewLine) {\r
-        //\r
-        // Don't print anything if it is a NULL help token\r
-        //\r
-        ASSERT(MenuOption != NULL);\r
-        HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;\r
-        if (HelpInfo == 0 || !IsSelectable (MenuOption)) {\r
+        if (IsListEmpty (&gMenuOption)) {\r
+          //\r
+          // Don't print anything if no mwnu option.\r
+          //\r
           StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
         } else {\r
-          StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);\r
+          //\r
+          // Don't print anything if it is a NULL help token\r
+          //\r
+          ASSERT(MenuOption != NULL);\r
+          HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;\r
+          if (HelpInfo == 0 || !IsSelectable (MenuOption)) {\r
+            StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
+          } else {\r
+            StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);\r
+          }\r
         }\r
 \r
         RowCount      = BottomRow - TopRow + 1;\r
@@ -2306,12 +2628,12 @@ UiDisplayMenu (
         // If the screen has no menu items, and the user didn't select UiReset\r
         // ignore the selection and go back to reading keys.\r
         //\r
+        ASSERT(MenuOption != NULL);\r
         if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
 \r
-        ASSERT(MenuOption != NULL);\r
         Statement = MenuOption->ThisTag;\r
         if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP)\r
           || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)\r
@@ -2408,9 +2730,9 @@ UiDisplayMenu (
       break;\r
 \r
     case CfScreenOperation:\r
-      if (ScreenOperation != UiReset) {\r
+      if ((ScreenOperation != UiReset) && (ScreenOperation != UiHotKey)) {\r
         //\r
-        // If the screen has no menu items, and the user didn't select UiReset\r
+        // If the screen has no menu items, and the user didn't select UiReset or UiHotKey\r
         // ignore the selection and go back to reading keys.\r
         //\r
         if (IsListEmpty (&gMenuOption)) {\r
@@ -2494,7 +2816,8 @@ UiDisplayMenu (
 \r
     case CfUiHotKey:\r
       ControlFlag = CfRepaint;\r
-      \r
+\r
+      ASSERT (HotKey != NULL);\r
       gUserInput->Action = HotKey->Action;\r
       ControlFlag = CfExit;\r
       break;\r
@@ -2529,184 +2852,108 @@ UiDisplayMenu (
 \r
     case CfUiUp:\r
       ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
 \r
       SavedListEntry = NewPos;\r
-\r
       ASSERT(NewPos != NULL);\r
+\r
+      MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+      ASSERT (MenuOption != NULL);\r
+\r
       //\r
       // Adjust Date/Time position before we advance forward.\r
       //\r
       AdjustDateAndTimePosition (TRUE, &NewPos);\r
-      if (NewPos->BackLink != &gMenuOption) {\r
-        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
-        ASSERT (MenuOption != NULL);\r
-        NewLine    = TRUE;\r
-        NewPos     = NewPos->BackLink;\r
 \r
-        PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (PreviousMenuOption->Row == 0) {\r
-          UpdateOptionSkipLines (PreviousMenuOption);\r
-        }\r
-        DistanceValue = PreviousMenuOption->Skip;\r
-        Difference    = 0;\r
-        if (MenuOption->Row >= DistanceValue + TopRow) {\r
-          Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
-        }\r
-        NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
-       \r
-        if (Difference < 0) {\r
+      NewPos     = NewPos->BackLink;\r
+      //\r
+      // Find next selectable menu or the first menu beyond current form.\r
+      //\r
+      Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow, FALSE);\r
+      if (Difference < 0) {\r
+        //\r
+        // We hit the begining MenuOption that can be focused\r
+        // so we simply scroll to the top.\r
+        //\r
+        Repaint     = TRUE;\r
+        if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          NewPos      = SavedListEntry;\r
+          SkipValue = 0;\r
+        } else {\r
           //\r
-          // We hit the begining MenuOption that can be focused\r
-          // so we simply scroll to the top.\r
+          // Scroll up to the last page when we have arrived at top page.\r
           //\r
-          if (TopOfScreen != gMenuOption.ForwardLink) {\r
-            TopOfScreen = gMenuOption.ForwardLink;\r
-            Repaint     = TRUE;\r
-          } else {\r
-            //\r
-            // Scroll up to the last page when we have arrived at top page.\r
-            //\r
-            NewPos          = &gMenuOption;\r
-            TopOfScreen     = &gMenuOption;\r
-            MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
-            ScreenOperation = UiPageUp;\r
-            ControlFlag     = CfScreenOperation;\r
-            break;\r
-          }\r
-        } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
+          TopOfScreen = FindTopOfScreenMenu (gMenuOption.BackLink, BottomRow - TopRow, &SkipValue);\r
+          NewPos = gMenuOption.BackLink;\r
+          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow, TRUE);\r
+        }\r
+      } else {\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+        if (MenuOption->Row < TopRow + Difference + NextMenuOption->Skip) {\r
           //\r
           // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
           //\r
           TopOfScreen = NewPos;\r
           Repaint     = TRUE;\r
-          SkipValue = 0;\r
-        } else if (!IsSelectable (NextMenuOption)) {\r
-          //\r
-          // Continue to go up until scroll to next page or the selectable option is found.\r
-          //\r
-          ScreenOperation = UiUp;\r
-          ControlFlag     = CfScreenOperation;\r
+          SkipValue   = 0;\r
         }\r
 \r
         //\r
-        // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
-        //\r
-        AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\r
-        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
-        UpdateStatusBar (INPUT_ERROR, FALSE);\r
-      } else {\r
-        //\r
-        // Scroll up to the last page.\r
+        // Check whether new highlight menu is selectable, if not, keep highlight on the old one.\r
         //\r
-        NewPos          = &gMenuOption;\r
-        TopOfScreen     = &gMenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
-        ScreenOperation = UiPageUp;\r
-        ControlFlag     = CfScreenOperation;\r
+        // BottomRow - TopRow + 1 means the total rows current forms supported.\r
+        // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu \r
+        // and new top menu. New top menu will all shows in next form, but last highlight menu \r
+        // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the \r
+        // last highlight menu.\r
+        // \r
+        if (!IsSelectable(NextMenuOption) && IsSelectable(MenuOption) && \r
+            (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {\r
+          NewPos = SavedListEntry;\r
+        }\r
       }\r
-      break;\r
 \r
-    case CfUiPageUp:\r
-      //\r
-      // SkipValue means lines is skipped when show the top menu option.\r
-      //\r
-      ControlFlag     = CfRepaint;\r
+      UpdateStatusBar (INPUT_ERROR, FALSE);\r
 \r
-      ASSERT(NewPos != NULL);\r
       //\r
-      // Already at the first menu option, Check the skip value.\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
       //\r
-      if (NewPos->BackLink == &gMenuOption) {\r
-        if (SkipValue == 0) {\r
-          NewLine = FALSE;\r
-          Repaint = FALSE;\r
-        } else {\r
-          NewLine = TRUE;\r
-          Repaint = TRUE;\r
-          SkipValue = 0;\r
-        }\r
-        break;\r
-      }\r
-\r
-      NewLine   = TRUE;\r
-      Repaint   = TRUE;\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
 \r
+    case CfUiPageUp:\r
       //\r
-      // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one\r
-      // form of options to be show, so just update the SkipValue to show the next\r
-      // parts of options.\r
+      // SkipValue means lines is skipped when show the top menu option.\r
       //\r
-      if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {\r
-        SkipValue -= BottomRow - TopRow + 1;\r
-        break;\r
-      }\r
+      ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
+      Repaint     = TRUE;\r
 \r
       Link      = TopOfScreen;\r
       //\r
       // First minus the menu of the top screen, it's value is SkipValue.\r
       //\r
-      Index     = (BottomRow + 1) - SkipValue;\r
-      while ((Index > TopRow) && (Link->BackLink != &gMenuOption)) {\r
-        Link = Link->BackLink;\r
-        PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-        if (PreviousMenuOption->Row == 0) {\r
-          UpdateOptionSkipLines (PreviousMenuOption);\r
-        }        \r
-        if (Index < PreviousMenuOption->Skip) {\r
-          break;\r
-        }\r
-        Index = Index - PreviousMenuOption->Skip;\r
-      }\r
-      \r
-      if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
-        SkipValue = 0;\r
-        if (TopOfScreen == &gMenuOption) {\r
-          TopOfScreen = gMenuOption.ForwardLink;\r
-          NewPos      = gMenuOption.BackLink;\r
-          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
-          Repaint = FALSE;\r
-        } else if (TopOfScreen != Link) {\r
-          TopOfScreen = Link;\r
-          NewPos      = Link;\r
-          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-        } else {\r
-          //\r
-          // Finally we know that NewPos is the last MenuOption can be focused.\r
-          //\r
-          Repaint = FALSE;\r
-          NewPos  = Link;\r
-          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-        }\r
-      } else {\r
-        if (Index > TopRow) {\r
-          //\r
-          // At here, only case "Index < PreviousMenuOption->Skip" can reach here.\r
-          //\r
-          SkipValue = PreviousMenuOption->Skip - (Index - TopRow);\r
-        } else if (Index == TopRow) {\r
-          SkipValue = 0;\r
-        } else {\r
-          SkipValue = TopRow - Index;\r
-        }\r
-\r
-        //\r
-        // Move to the option in Next page.\r
+      if (SkipValue >= BottomRow - TopRow + 1) {\r
         //\r
-        if (TopOfScreen == &gMenuOption) {\r
-          NewPos = gMenuOption.BackLink;\r
-          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
-        } else {\r
-          NewPos = Link;\r
-          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-        }\r
-\r
+        // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one\r
+        // form of options to be show, so just update the SkipValue to show the next\r
+        // parts of options.\r
         //\r
-        // There are more MenuOption needing scrolling up.\r
-        //\r
-        TopOfScreen = Link;\r
-        MenuOption  = NULL;\r
+        SkipValue -= BottomRow - TopRow + 1;\r
+        NewPos     = TopOfScreen;\r
+        break;\r
+      } else {\r
+        Index     = (BottomRow + 1) - SkipValue - TopRow;\r
       }\r
+      \r
+      TopOfScreen = FindTopOfScreenMenu(TopOfScreen, Index, &SkipValue);\r
+      NewPos = TopOfScreen;\r
+      MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, FALSE);\r
+      \r
+      UpdateStatusBar (INPUT_ERROR, FALSE);\r
 \r
       //\r
       // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
@@ -2720,17 +2967,10 @@ UiDisplayMenu (
       //\r
       // SkipValue means lines is skipped when show the top menu option.\r
       //\r
-      ControlFlag     = CfRepaint;\r
-\r
-      ASSERT (NewPos != NULL);\r
-      if (NewPos->ForwardLink == &gMenuOption) {\r
-        NewLine = FALSE;\r
-        Repaint = FALSE;\r
-        break;\r
-      }\r
+      ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
+      Repaint     = TRUE;\r
 \r
-      NewLine = TRUE;\r
-      Repaint = TRUE;\r
       Link    = TopOfScreen;\r
       NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       Index = TopRow + NextMenuOption->Skip - SkipValue;\r
@@ -2745,10 +2985,10 @@ UiDisplayMenu (
 \r
       if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
         //\r
-        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        // Highlight on the last menu which can be highlight.\r
         //\r
         Repaint = FALSE;\r
-        MoveToNextStatement (TRUE, &Link, Index - TopRow);\r
+        MoveToNextStatement (TRUE, &Link, Index - TopRow, TRUE);\r
       } else {\r
         //\r
         // Calculate the skip line for top of screen menu.\r
@@ -2761,13 +3001,12 @@ UiDisplayMenu (
         } else {\r
           SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
         }\r
-\r
         TopOfScreen = Link;\r
         MenuOption = NULL;\r
         //\r
         // Move to the Next selectable menu.\r
         //\r
-        MoveToNextStatement (FALSE, &Link, BottomRow - TopRow);\r
+        MoveToNextStatement (FALSE, &Link, BottomRow - TopRow, TRUE);\r
       }\r
 \r
       //\r
@@ -2775,6 +3014,8 @@ UiDisplayMenu (
       //\r
       NewPos  = Link;\r
 \r
+      UpdateStatusBar (INPUT_ERROR, FALSE);\r
+\r
       //\r
       // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
       // Don't do this when we are already in the last page.\r
@@ -2789,7 +3030,15 @@ UiDisplayMenu (
       // NewPos  points to the menu which is highlighted now.\r
       //\r
       ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
+\r
+      if (NewPos == TopOfScreen) {\r
+        Temp2 = SkipValue;\r
+      } else {\r
+        Temp2 = 0;\r
+      }\r
 \r
+      SavedListEntry = NewPos;\r
       //\r
       // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
       // to be one that progresses to the next set of op-codes, we need to advance to the last\r
@@ -2798,176 +3047,134 @@ UiDisplayMenu (
       // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
       // the Date/Time op-code.\r
       //\r
-      SavedListEntry = NewPos;\r
       AdjustDateAndTimePosition (FALSE, &NewPos);\r
 \r
-      if (NewPos->ForwardLink != &gMenuOption) {\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        NewLine         = TRUE;\r
-        NewPos          = NewPos->ForwardLink;\r
-\r
-        Difference      = 0;\r
+      MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+      NewPos     = NewPos->ForwardLink;\r
+      //\r
+      // Find the next selectable menu.\r
+      //\r
+      if (MenuOption->Row + MenuOption->Skip - Temp2 > BottomRow + 1) {\r
+        if (gMenuOption.ForwardLink == NewPos || &gMenuOption == NewPos) {\r
+          Difference = -1;\r
+        } else {\r
+          Difference = 0;\r
+        }\r
+      } else {\r
+        Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow + 1 - (MenuOption->Row + MenuOption->Skip - Temp2), FALSE);\r
+      }\r
+      if (Difference < 0) {\r
         //\r
-        // Current menu not at the bottom of the form.\r
+        // Scroll to the first page.\r
         //\r
-        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
-          //\r
-          // Find the next selectable menu.\r
-          //\r
-          Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
-          //\r
-          // We hit the end of MenuOption that can be focused\r
-          // so we simply scroll to the first page.\r
-          //\r
-          if (Difference < 0) {\r
-            //\r
-            // Scroll to the first page.\r
-            //\r
-            if (TopOfScreen != gMenuOption.ForwardLink) {\r
-              TopOfScreen = gMenuOption.ForwardLink;\r
-              Repaint     = TRUE;\r
-              MenuOption  = NULL;\r
-            } else {\r
-              MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
-            }\r
-            NewPos        = gMenuOption.ForwardLink;\r
-            MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-\r
-            SkipValue = 0;\r
-            //\r
-            // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
-            //\r
-            AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
-            AdjustDateAndTimePosition (TRUE, &NewPos);\r
-            break;\r
-          }\r
-        }\r
-        NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (NextMenuOption->Row == 0) {\r
-          UpdateOptionSkipLines (NextMenuOption);\r
-        }\r
-        DistanceValue  = Difference + NextMenuOption->Skip;\r
-\r
-        Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
-        if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
-            (NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP ||\r
-             NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)\r
-            ) {\r
-          Temp ++;\r
+        if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) { \r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          Repaint     = TRUE;\r
+          MenuOption  = NULL;\r
+        } else {\r
+          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
         }\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);\r
 \r
+        SkipValue = 0;\r
         //\r
-        // If we are going to scroll, update TopOfScreen\r
+        // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
         //\r
-        if (Temp > BottomRow) {\r
-          do {\r
-            //\r
-            // Is the current top of screen a zero-advance op-code?\r
-            // If so, keep moving forward till we hit a >0 advance op-code\r
-            //\r
-            SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+        AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        break;\r
+      }        \r
 \r
-            //\r
-            // If bottom op-code is more than one line or top op-code is more than one line\r
-            //\r
-            if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) {\r
-              //\r
-              // Is the bottom op-code greater than or equal in size to the top op-code?\r
-              //\r
-              if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {\r
-                //\r
-                // Skip the top op-code\r
-                //\r
-                TopOfScreen     = TopOfScreen->ForwardLink;\r
-                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
-\r
-                SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
-\r
-                //\r
-                // If we have a remainder, skip that many more op-codes until we drain the remainder\r
-                //\r
-                while (Difference >= (INTN) SavedMenuOption->Skip) {\r
-                  //\r
-                  // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
-                  //\r
-                  Difference      = Difference - (INTN) SavedMenuOption->Skip;\r
-                  TopOfScreen     = TopOfScreen->ForwardLink;\r
-                  SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
-                }\r
-                //\r
-                // Since we will act on this op-code in the next routine, and increment the\r
-                // SkipValue, set the skips to one less than what is required.\r
-                //\r
-                SkipValue = Difference - 1;\r
-              } else {\r
-                //\r
-                // Since we will act on this op-code in the next routine, and increment the\r
-                // SkipValue, set the skips to one less than what is required.\r
-                //\r
-                SkipValue += (Temp - BottomRow) - 1;\r
-              }\r
-            } else {\r
-              if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
-                TopOfScreen = TopOfScreen->ForwardLink;\r
-                break;\r
-              }\r
-            }\r
-            //\r
-            // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
-            // Let's set a skip flag to smoothly scroll the top of the screen.\r
-            //\r
-            if (SavedMenuOption->Skip > 1) {\r
-              if (SavedMenuOption == NextMenuOption) {\r
-                SkipValue = 0;\r
-              } else {\r
-                SkipValue++;\r
-              }\r
-            } else if (SavedMenuOption->Skip == 1) {\r
-              SkipValue   = 0;\r
-            } else {\r
-              SkipValue   = 0;\r
-              TopOfScreen = TopOfScreen->ForwardLink;\r
-            }\r
-          } while (SavedMenuOption->Skip == 0);\r
+      //\r
+      // Get next selected menu info.\r
+      //\r
+      AdjustDateAndTimePosition (FALSE, &NewPos);\r
+      NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
+      if (NextMenuOption->Row == 0) {\r
+        UpdateOptionSkipLines (NextMenuOption);\r
+      }\r
 \r
-          Repaint       = TRUE;\r
-        } else if (!IsSelectable (NextMenuOption)) {\r
+      //\r
+      // Calculate new highlight menu end row.\r
+      //\r
+      Temp = (MenuOption->Row + MenuOption->Skip - Temp2) + Difference + NextMenuOption->Skip - 1;\r
+      if (Temp > BottomRow) {\r
+        //\r
+        // Get the top screen menu info.\r
+        //\r
+        AdjustDateAndTimePosition (FALSE, &TopOfScreen);\r
+        SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+\r
+        //\r
+        // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.\r
+        // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.\r
+        //\r
+        if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {\r
           //\r
-          // Continue to go down until scroll to next page or the selectable option is found.\r
+          // Skip the top op-code\r
           //\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
-        }\r
+          TopOfScreen   = TopOfScreen->ForwardLink;\r
+          DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
 \r
-        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+          SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
 \r
-        UpdateStatusBar (INPUT_ERROR, FALSE);\r
-\r
-      } else {\r
-        //\r
-        // Scroll to the first page.\r
-        //\r
-        if (TopOfScreen != gMenuOption.ForwardLink) {\r
-          TopOfScreen = gMenuOption.ForwardLink;\r
-          Repaint     = TRUE;\r
-          MenuOption  = NULL;\r
+          //\r
+          // If we have a remainder, skip that many more op-codes until we drain the remainder\r
+          // Special case is the selected highlight menu has more than one form of menus.\r
+          //\r
+          while (DistanceValue >= SavedMenuOption->Skip && TopOfScreen != NewPos) {\r
+            //\r
+            // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
+            //\r
+            DistanceValue   = DistanceValue - (INTN) SavedMenuOption->Skip;\r
+            TopOfScreen     = TopOfScreen->ForwardLink;\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+          }\r
+          //\r
+          // Since we will act on this op-code in the next routine, and increment the\r
+          // SkipValue, set the skips to one less than what is required.\r
+          //\r
+          if (TopOfScreen != NewPos) {\r
+            SkipValue = DistanceValue;\r
+          } else {\r
+            SkipValue = 0;\r
+          }\r
         } else {\r
           //\r
-          // Need to remove the current highlight menu.\r
-          // MenuOption saved the last highlight menu info.\r
+          // Since we will act on this op-code in the next routine, and increment the\r
+          // SkipValue, set the skips to one less than what is required.\r
           //\r
-          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+          SkipValue += Temp - BottomRow;\r
         }\r
-\r
-        SkipValue     = 0;\r
-        NewLine       = TRUE;\r
+        Repaint       = TRUE;\r
+      } else if (!IsSelectable (NextMenuOption)) {\r
         //\r
-        // Get the next highlight menu.\r
+        // Continue to go down until scroll to next page or the selectable option is found.\r
         //\r
-        NewPos        = gMenuOption.ForwardLink;\r
-        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+        ScreenOperation = UiDown;\r
+        ControlFlag     = CfScreenOperation;\r
+        break;\r
+      }\r
+\r
+      MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+\r
+      //\r
+      // Check whether new highlight menu is selectable, if not, keep highlight on the old one.\r
+      //\r
+      // BottomRow - TopRow + 1 means the total rows current forms supported.\r
+      // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu \r
+      // and new top menu. New top menu will all shows in next form, but last highlight menu \r
+      // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the \r
+      // last highlight menu.\r
+      // \r
+      if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) && \r
+         (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {\r
+        NewPos = SavedListEntry;\r
       }\r
 \r
+      UpdateStatusBar (INPUT_ERROR, FALSE);\r
+\r
       //\r
       // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
       //\r
@@ -3008,14 +3215,56 @@ BrowserStatusProcess (
   VOID\r
   )\r
 {\r
-  CHAR16         *ErrorInfo;\r
-  EFI_INPUT_KEY  Key;\r
+  CHAR16             *ErrorInfo;\r
+  EFI_INPUT_KEY      Key;\r
+  EFI_EVENT          WaitList[2];\r
+  EFI_EVENT          RefreshIntervalEvent;\r
+  EFI_EVENT          TimeOutEvent;\r
+  UINT8              TimeOut;\r
+  EFI_STATUS         Status;\r
+  UINTN              Index;\r
+  WARNING_IF_CONTEXT EventContext;\r
+  EFI_IFR_OP_HEADER  *OpCodeBuf;\r
+  EFI_STRING_ID      StringToken;\r
+  CHAR16             DiscardChange;\r
+  CHAR16             JumpToFormSet;\r
+  CHAR16             *PrintString;\r
 \r
   if (gFormData->BrowserStatus == BROWSER_SUCCESS) {\r
     return;\r
   }\r
 \r
-  if (gFormData->ErrorString != NULL) {\r
+  StringToken          = 0;\r
+  TimeOutEvent         = NULL;\r
+  RefreshIntervalEvent = NULL;\r
+  OpCodeBuf            = NULL;\r
+  if (gFormData->HighLightedStatement != NULL) {\r
+    OpCodeBuf = gFormData->HighLightedStatement->OpCode;\r
+  }\r
+\r
+  if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {\r
+    ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);\r
+\r
+    TimeOut     = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->TimeOut;\r
+    StringToken = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->Warning;\r
+  } else {\r
+    TimeOut = 0;\r
+    if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&\r
+        (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)) {\r
+      StringToken = ((EFI_IFR_NO_SUBMIT_IF *) OpCodeBuf)->Error;\r
+    } else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&\r
+               (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)) {\r
+      StringToken = ((EFI_IFR_INCONSISTENT_IF *) OpCodeBuf)->Error;\r
+    }\r
+  }\r
+\r
+  if (StringToken != 0) {\r
+    ErrorInfo = GetToken (StringToken, gFormData->HiiHandle);\r
+  } else if (gFormData->ErrorString != NULL) {\r
+    //\r
+    // Only used to compatible with old setup browser.\r
+    // Not use this field in new browser core.\r
+    //\r
     ErrorInfo = gFormData->ErrorString;\r
   } else {\r
     switch (gFormData->BrowserStatus) {\r
@@ -3023,10 +3272,6 @@ BrowserStatusProcess (
       ErrorInfo = gSaveFailed;\r
       break;\r
 \r
-    case BROWSER_NO_SUBMIT_IF:\r
-      ErrorInfo = gNoSubmitIf;\r
-      break;\r
-\r
     case BROWSER_FORM_NOT_FOUND:\r
       ErrorInfo = gFormNotFound;\r
       break;\r
@@ -3039,18 +3284,98 @@ BrowserStatusProcess (
       ErrorInfo = gProtocolNotFound;\r
       break;\r
 \r
+    case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:\r
+      ErrorInfo = gNoSubmitIfFailed;\r
+      break;\r
+\r
     default:\r
       ErrorInfo = gBrwoserError;\r
       break;\r
     }\r
   }\r
 \r
-  //\r
-  // Error occur, prompt error message.\r
-  //\r
-  do {\r
-    CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);\r
-  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  switch (gFormData->BrowserStatus) {\r
+  case BROWSER_SUBMIT_FAIL:\r
+  case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:\r
+    ASSERT (gUserInput != NULL);\r
+    if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) {\r
+      PrintString = gSaveProcess;\r
+      JumpToFormSet = gJumpToFormSet[0];\r
+    } else {\r
+      PrintString = gSaveNoSubmitProcess;\r
+      JumpToFormSet = gCheckError[0];\r
+    }\r
+    DiscardChange = gDiscardChange[0];\r
+\r
+    do {\r
+      CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL);\r
+    } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) &&\r
+             ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET)));\r
+\r
+    if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) {\r
+      gUserInput->Action = BROWSER_ACTION_DISCARD;\r
+    } else {\r
+      gUserInput->Action = BROWSER_ACTION_GOTO;\r
+    }\r
+    break;\r
+\r
+  default:\r
+    if (TimeOut == 0) {\r
+      do {\r
+        CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    } else {\r
+      Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      EventContext.SyncEvent = TimeOutEvent;\r
+      EventContext.TimeOut   = &TimeOut;\r
+      EventContext.ErrorInfo = ErrorInfo;\r
+\r
+      Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      //\r
+      // Show the dialog first to avoid long time not reaction.\r
+      //\r
+      gBS->SignalEvent (RefreshIntervalEvent);\r
+    \r
+      Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      while (TRUE) {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        if (!EFI_ERROR (Status) && Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          break;\r
+        }\r
+\r
+        if (Status != EFI_NOT_READY) {\r
+          continue;\r
+        }\r
+\r
+        WaitList[0] = TimeOutEvent;\r
+        WaitList[1] = gST->ConIn->WaitForKey;\r
+\r
+        Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (Index == 0) {\r
+          //\r
+          // Timeout occur, close the hoot time out event.\r
+          //\r
+          break;\r
+        }\r
+      }\r
+\r
+      gBS->CloseEvent (TimeOutEvent);\r
+      gBS->CloseEvent (RefreshIntervalEvent);\r
+    }\r
+    break;\r
+  }\r
+\r
+  if (StringToken != 0) {\r
+    FreePool (ErrorInfo);\r
+  }\r
 }\r
 \r
 /**\r
@@ -3085,9 +3410,9 @@ FormDisplay (
   // Process the status info first.\r
   //\r
   BrowserStatusProcess();\r
-  if (UserInputData == NULL) {\r
+  if (gFormData->BrowserStatus != BROWSER_SUCCESS) {\r
     //\r
-    // UserInputData == NULL, means only need to print the error info, return here.\r
+    // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.\r
     //\r
     return EFI_SUCCESS;\r
   }\r
@@ -3251,5 +3576,9 @@ UnloadDisplayEngine (
 \r
   FreeDisplayStrings ();\r
 \r
+  if (gHighligthMenuInfo.OpCode != NULL) {\r
+    FreePool (gHighligthMenuInfo.OpCode);\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r