]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
Update code to support guid op nest in the statement.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
index 8e5b890bf359dfed1e5328253735dc3ae2b480b1..7130dffdc3091863f506ac8d967b1ee025750e68 100644 (file)
@@ -259,7 +259,7 @@ 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
@@ -267,19 +267,26 @@ GetPrompt (
 **/\r
 UINT16\r
 GetWidth (\r
-  IN FORM_DISPLAY_ENGINE_STATEMENT        *Statement,\r
-  OUT UINT16                              *AdjustWidth\r
+  IN  UI_MENU_OPTION     *MenuOption,\r
+  OUT UINT16             *AdjustWidth\r
   )\r
 {\r
-  CHAR16       *String;\r
-  UINTN        Size;\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
-    return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - gModalSkipColumn - SCROLL_ARROW_HEIGHT);\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
@@ -316,13 +323,23 @@ GetWidth (
     //\r
     // Keep consistent with current behavior.\r
     //\r
-    return (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);\r
+    ReturnWidth = (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);\r
+  } else {\r
+    if (AdjustWidth != NULL) {\r
+      *AdjustWidth = 1;\r
+    }\r
+\r
+    ReturnWidth =  (UINT16) (gPromptBlockWidth - 1);\r
   }\r
 \r
-  if (AdjustWidth != NULL) {\r
-    *AdjustWidth = 1;\r
+  //\r
+  // For nest in statement, should the subtitle indent.\r
+  //\r
+  if (MenuOption->NestInStatement) {\r
+    ReturnWidth -= SUBTITLE_INDENT;\r
   }\r
-  return (UINT16) (gPromptBlockWidth - 1);\r
+\r
+  return ReturnWidth;\r
 }\r
 \r
 /**\r
@@ -536,24 +553,7 @@ UiAddMenuOption (
   String = GetToken (PromptId, gFormData->HiiHandle);\r
   ASSERT (String != NULL);\r
 \r
-  Width  = GetWidth (Statement, 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
-\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
@@ -568,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
@@ -630,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
@@ -676,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
@@ -829,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
@@ -846,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
@@ -861,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
@@ -883,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
@@ -894,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
@@ -924,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
@@ -1332,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
@@ -1346,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
@@ -1367,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
@@ -1408,53 +1529,17 @@ FindTopMenu (
     //\r
     // Still show the highlight menu before exit from display engine.\r
     //\r
-    EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
-  } else {\r
-    EndRow = BottomRow;\r
+    BottomRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
   }\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
-  //\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
-\r
-  //\r
-  // Found the menu which will show at the top of the page.\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
+  if (SavedMenuOption->Skip >= BottomRow - TopRow) {\r
+    TmpValue = 0;\r
+    *TopOfScreen = NewPos;\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
-    }\r
+    *TopOfScreen = FindTopOfScreenMenu(NewPos, BottomRow - TopRow - SavedMenuOption->Skip, &TmpValue);\r
   }\r
+\r
+  *SkipValue   = TmpValue;\r
 }\r
 \r
 /**\r
@@ -1574,6 +1659,58 @@ DisplayMenuString (
   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
@@ -1604,7 +1741,6 @@ DisplayOneMenu (
   CHAR16                          *StringPtr;\r
   CHAR16                          *OptionString;\r
   CHAR16                          *OutputString;\r
-  UINTN                           OriginalRow;\r
   UINT16                          GlyphWidth;\r
   UINTN                           Temp;\r
   UINTN                           Temp2;\r
@@ -1613,15 +1749,18 @@ DisplayOneMenu (
   UINTN                           Row;\r
   UINTN                           Col;\r
   UINTN                           PromptLineNum;\r
+  UINTN                           OptionLineNum;\r
   CHAR16                          AdjustValue;\r
+  UINTN                           MaxRow;\r
 \r
   Statement = MenuOption->ThisTag;\r
-  Col       = MenuOption->Col;\r
-  Row       = MenuOption->Row;\r
   Temp      = SkipLine;\r
   Temp2     = SkipLine;\r
   Temp3     = SkipLine;\r
-  AdjustValue = 0;\r
+  AdjustValue   = 0;\r
+  PromptLineNum = 0;\r
+  OptionLineNum = 0;\r
+  MaxRow        = 0;\r
 \r
   //\r
   // Set default color.\r
@@ -1645,8 +1784,9 @@ DisplayOneMenu (
     }\r
   \r
     Width       = (UINT16) gOptionBlockWidth - 1;\r
-    OriginalRow = Row;\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
@@ -1671,6 +1811,7 @@ DisplayOneMenu (
         } else {\r
           DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);\r
         }\r
+        OptionLineNum++;\r
       }\r
       \r
       //\r
@@ -1686,7 +1827,7 @@ DisplayOneMenu (
           //\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
+          if ((Row - MenuOption->Row) >= MenuOption->Skip) {\r
             MenuOption->Skip++;\r
           }\r
         }\r
@@ -1698,50 +1839,22 @@ DisplayOneMenu (
       }\r
     }\r
   \r
-    Row   = OriginalRow;\r
     Highlight = FALSE;\r
 \r
     FreePool (OptionString);\r
   }\r
-  Temp2 = 0;\r
-\r
 \r
   //\r
-  // 2. Pre calculate the skip value.\r
+  // 2. Paint the description.\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
-    OriginalRow = Row;\r
-    GlyphWidth    = 1;\r
-    for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) { \r
-      if (StrLen (&StringPtr[Index]) != 0) {\r
-        Row++;\r
-        if ((Row - OriginalRow) >= MenuOption->Skip) {\r
-          MenuOption->Skip++;\r
-        }\r
-      }\r
-      FreePool (OutputString);\r
-    }\r
-  \r
-    Row = OriginalRow;\r
-    FreePool (StringPtr);\r
-  }\r
-\r
-\r
-  //\r
-  // 3. Paint the description.\r
-  //\r
-  PromptWidth   = GetWidth (Statement, &AdjustValue);\r
-  OriginalRow   = Row;\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
-    while (Temp++ < MenuOption->Skip) {\r
-      PrintStringAtWithWidth (BeginCol, Row++, L"", PromptWidth + AdjustValue + SkipWidth);\r
-    } \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
@@ -1779,34 +1892,24 @@ DisplayOneMenu (
     }\r
 \r
     Highlight = FALSE;\r
-\r
-    //\r
-    // Clean the empty prompt line.\r
-    // These line is used by option string but not prompt, so clean them here.\r
-    //\r
-    Row = OriginalRow + PromptLineNum;\r
-    while (PromptLineNum + SkipLine < MenuOption->Skip && Row <= BottomRow) {\r
-      PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);\r
-      PromptLineNum ++;\r
-      Row ++;\r
-    }\r
   }\r
-  Row = OriginalRow;\r
 \r
 \r
   //\r
-  // 4. If this is a text op with secondary text information\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
-    OriginalRow = Row;\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
@@ -1814,6 +1917,12 @@ DisplayOneMenu (
       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
@@ -1822,11 +1931,25 @@ DisplayOneMenu (
         Temp3--;\r
       }\r
     }\r
-  \r
-    Row = OriginalRow;\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
@@ -1846,7 +1969,7 @@ UiDisplayMenu (
   IN  FORM_DISPLAY_ENGINE_FORM  *FormData\r
   )\r
 {\r
-  INTN                            SkipValue;\r
+  UINTN                           SkipValue;\r
   INTN                            Difference;\r
   UINTN                           DistanceValue;\r
   UINTN                           Row;\r
@@ -1855,7 +1978,6 @@ UiDisplayMenu (
   UINTN                           Temp2;\r
   UINTN                           TopRow;\r
   UINTN                           BottomRow;\r
-  UINTN                           OriginalRow;\r
   UINTN                           Index;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
@@ -1890,7 +2012,6 @@ UiDisplayMenu (
   UINTN                           HelpHeaderLine;\r
   UINTN                           HelpBottomLine;\r
   BOOLEAN                         MultiHelpPage;\r
-  UINT16                          GlyphWidth;\r
   UINT16                          EachLineWidth;\r
   UINT16                          HeaderLineWidth;\r
   UINT16                          BottomLineWidth;\r
@@ -1999,9 +2120,12 @@ UiDisplayMenu (
         if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
           UpArrow = TRUE;\r
         }\r
-        \r
-        PrintStringAtWithWidth(gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\r
 \r
+        if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+          PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);\r
+        } else {\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
@@ -2036,15 +2160,28 @@ UiDisplayMenu (
             SavedMenuOption = MenuOption;\r
             SkipHighLight   = TRUE;\r
           }\r
-          \r
-          DisplayOneMenu (MenuOption, \r
-                          ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) ? LEFT_SKIPPED_COLUMNS + gModalSkipColumn : LEFT_SKIPPED_COLUMNS,\r
-                          gStatementDimensions.LeftColumn, \r
-                          Link == TopOfScreen ? SkipValue : 0, \r
-                          BottomRow,\r
-                          Link == NewPos && IsSelectable(MenuOption)\r
-                          );\r
 \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
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
           //\r
           // 3. Update the row info which will be used by next menu.\r
           //\r
@@ -2069,7 +2206,7 @@ UiDisplayMenu (
         //\r
         while (Row <= BottomRow) {\r
           if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
-            PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\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
@@ -2078,8 +2215,11 @@ UiDisplayMenu (
         //\r
         // 4. Print the down arrow row.\r
         //\r
-        PrintStringAtWithWidth(gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);\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
         if (DownArrow) {\r
           gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
           PrintCharAt (\r
@@ -2091,10 +2231,6 @@ UiDisplayMenu (
         }\r
 \r
         MenuOption = NULL;\r
-\r
-        if (IsListEmpty (&gMenuOption)) { \r
-          ControlFlag = CfReadKey;\r
-        }\r
       }\r
       break;\r
 \r
@@ -2114,6 +2250,14 @@ UiDisplayMenu (
         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
@@ -2128,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, NULL);\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
@@ -2215,79 +2295,13 @@ UiDisplayMenu (
           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, NULL);\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
-        //\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
@@ -2297,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
@@ -2530,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
@@ -2632,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
@@ -2718,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
@@ -2753,6 +2779,7 @@ UiDisplayMenu (
 \r
     case CfUiUp:\r
       ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
 \r
       SavedListEntry = NewPos;\r
 \r
@@ -2761,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
@@ -2944,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
@@ -2969,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
@@ -2985,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
@@ -2999,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
@@ -3013,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
@@ -3022,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