]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
Fix a bug for vlan ping failure.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
index a07cc75a47c2c44755a268bf5119d0f1cf9695c4..7130dffdc3091863f506ac8d967b1ee025750e68 100644 (file)
@@ -130,6 +130,7 @@ CHAR16            *gOptionMismatch;
 CHAR16            *gFormSuppress;\r
 CHAR16            *gProtocolNotFound;\r
 \r
+CHAR16            gModalSkipColumn;\r
 CHAR16            gPromptBlockWidth;\r
 CHAR16            gOptionBlockWidth;\r
 CHAR16            gHelpBlockWidth;\r
@@ -258,20 +259,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 +313,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 +553,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 +568,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 +622,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 +699,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 +859,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 +924,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 +939,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 +966,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 +982,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 +1008,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 +1403,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,16 +1469,14 @@ 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
   TopRow    = gStatementDimensions.TopRow    + SCROLL_ARROW_HEIGHT;\r
   BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
@@ -1347,7 +1488,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
@@ -1388,83 +1529,455 @@ FindTopMenu (
     //\r
     // Still show the highlight menu before exit from display engine.\r
     //\r
-    EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+    BottomRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+  }\r
+\r
+  if (SavedMenuOption->Skip >= BottomRow - TopRow) {\r
+    TmpValue = 0;\r
+    *TopOfScreen = NewPos;\r
   } else {\r
-    EndRow = BottomRow;\r
+    *TopOfScreen = FindTopOfScreenMenu(NewPos, BottomRow - TopRow - SavedMenuOption->Skip, &TmpValue);\r
   }\r
 \r
+  *SkipValue   = TmpValue;\r
+}\r
+\r
+/**\r
+  Update highlight menu info.\r
+\r
+  @param  MenuOption               The menu opton which is highlight.\r
+\r
+**/\r
+VOID\r
+UpdateHighlightMenuInfo (\r
+  IN UI_MENU_OPTION            *MenuOption\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
+  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
+\r
+  RefreshKeyHelp(gFormData, Statement, FALSE);\r
+}\r
+\r
+/**\r
+  Update attribut for this menu.\r
+\r
+  @param  MenuOption               The menu opton which this attribut used to.\r
+  @param  Highlight                Whether this menu will be highlight.\r
+\r
+**/\r
+VOID\r
+SetDisplayAttribute (\r
+  IN UI_MENU_OPTION                  *MenuOption,\r
+  IN BOOLEAN                         Highlight\r
+  )\r
+{\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
+  \r
+  Statement = MenuOption->ThisTag;\r
+\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
-    SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-    UpdateOptionSkipLines (SavedMenuOption);\r
-    Index += SavedMenuOption->Skip;\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
-  // Found the menu which will show at the top of the page.\r
+  // Second, clean the empty after the string.\r
   //\r
-  if (Link == NewPos) {\r
-    //\r
-    // The menu can show more than one pages, just show the menu at the top of the page.\r
-    //\r
-    *SkipValue    = 0;\r
-    *TopOfScreen  = Link;\r
-  } else {\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
-    // Check whether need to skip some line for menu shows at the top of the page.\r
+    // Allow a wide display if text op-code and no secondary text op-code\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
-    }\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
-  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
+  Print string for this menu option.\r
 \r
-  @param  FormData               The current form data info.\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
 \r
-  @retval EFI_SUCESSS            Process the user selection success.\r
-  @retval EFI_NOT_FOUND          Process option string for orderedlist/Oneof fail.\r
+  @retval EFI_SUCESSS              Process the user selection success.\r
 \r
 **/\r
 EFI_STATUS\r
-UiDisplayMenu (\r
-  IN  FORM_DISPLAY_ENGINE_FORM  *FormData\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
   )\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
+  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, TRUE);\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
+            //                \r
+            DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString), 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                           OriginalRow;\r
   UINTN                           Index;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
@@ -1491,7 +2004,6 @@ UiDisplayMenu (
   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
@@ -1500,13 +2012,13 @@ UiDisplayMenu (
   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
+  BOOLEAN                         SkipHighLight;\r
 \r
   EventType           = UIEventNone;\r
   Status              = EFI_SUCCESS;\r
@@ -1531,6 +2043,7 @@ UiDisplayMenu (
   UpArrow             = FALSE;\r
   DownArrow           = FALSE;\r
   SkipValue           = 0;\r
+  SkipHighLight       = FALSE;\r
 \r
   NextMenuOption      = NULL;\r
   PreviousMenuOption  = NULL;\r
@@ -1538,21 +2051,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 +2084,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 +2112,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 +2144,44 @@ 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
+                            );\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
+                            );         \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 +2201,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 +2243,21 @@ UiDisplayMenu (
       //\r
       ControlFlag = CfUpdateHelpString;\r
 \r
+      if (SkipHighLight) {\r
+        MenuOption    = SavedMenuOption;\r
+        SkipHighLight = FALSE;\r
+        UpdateHighlightMenuInfo (MenuOption);\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 +2272,15 @@ 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
+                          );\r
         }\r
 \r
         //\r
@@ -1967,103 +2289,19 @@ 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);\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
+                        );\r
       }\r
       break;\r
 \r
@@ -2073,16 +2311,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 +2555,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 +2657,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 +2743,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,6 +2779,7 @@ UiDisplayMenu (
 \r
     case CfUiUp:\r
       ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
 \r
       SavedListEntry = NewPos;\r
 \r
@@ -2537,176 +2788,99 @@ UiDisplayMenu (
       // 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
+      MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+      ASSERT (MenuOption != NULL);\r
+\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
+        // Check whether new highlight menu is selectable, if not, keep highlight on the old one.\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
-        //\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 +2894,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 +2912,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 +2928,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 +2941,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 +2957,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 +2974,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
-\r
-        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+          TopOfScreen   = TopOfScreen->ForwardLink;\r
+          DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
 \r
-        UpdateStatusBar (INPUT_ERROR, FALSE);\r
+          SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\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