]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
MdeModulePkg: Fixed 'variable set but not used' build warning.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index ebe8fae2cc4391812cc948a29cb2f25f1719dd20..d54466e1230e65207c0499eb2d1d03e43e307c8f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Utility functions for User Interface functions.\r
 \r
-Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -439,7 +439,7 @@ RefreshQuestion (
   Selection = MenuRefreshEntry->Selection;\r
   Question = MenuRefreshEntry->MenuOption->ThisTag;\r
 \r
-  Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
+  Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -731,8 +731,10 @@ UiAddMenuOption (
     }\r
     MenuOption->Sequence = Index;\r
 \r
-    if (Statement->GrayOutExpression != NULL) {\r
-      MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut ) {\r
+      MenuOption->GrayOut = TRUE;\r
+    } else {\r
+      MenuOption->GrayOut = FALSE;\r
     }\r
 \r
     //\r
@@ -765,7 +767,9 @@ UiAddMenuOption (
         //\r
         MenuOption->GrayOut = TRUE;\r
       }\r
-\r
+      //\r
+      // break skipped on purpose\r
+      //\r
     default:\r
       MenuOption->IsQuestion = FALSE;\r
       break;\r
@@ -774,6 +778,9 @@ UiAddMenuOption (
     if ((Statement->ValueExpression != NULL) ||\r
         ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
       MenuOption->ReadOnly = TRUE;\r
+      if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
     }\r
 \r
     InsertTailList (&gMenuOption, &MenuOption->Link);\r
@@ -850,8 +857,6 @@ CreateDialog (
   ASSERT (TempString);\r
   ASSERT (BufferedString);\r
 \r
-  VA_START (Marker, KeyValue);\r
-\r
   //\r
   // Zero the outgoing buffer\r
   //\r
@@ -873,6 +878,8 @@ CreateDialog (
 \r
   LargestString = 0;\r
 \r
+  VA_START (Marker, KeyValue);\r
+\r
   //\r
   // Determine the largest string in the dialog box\r
   // Notice we are starting with 1 since String is the first string\r
@@ -953,6 +960,9 @@ CreateDialog (
           TempString[Index - 1] = CHAR_NULL;\r
           StrCpy (StringBuffer, TempString);\r
         }\r
+        //\r
+        // break skipped on purpose\r
+        //\r
 \r
       default:\r
         //\r
@@ -1306,101 +1316,174 @@ GetWidth (
 /**\r
   Will copy LineWidth amount of a string in the OutputString buffer and return the\r
   number of CHAR16 characters that were copied into the OutputString buffer.\r
+  The output string format is:\r
+    Glyph Info + String info + '\0'.\r
+\r
+  In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
 \r
   @param  InputString            String description for this option.\r
   @param  LineWidth              Width of the desired string to extract in CHAR16\r
                                  characters\r
+  @param  GlyphWidth             The glyph width of the begin of the char in the string.\r
   @param  Index                  Where in InputString to start the copy process\r
   @param  OutputString           Buffer to copy the string into\r
 \r
-  @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
+  @return Returns the number of CHAR16 characters that were copied into the OutputString \r
+  buffer, include extra glyph info and '\0' info.\r
 \r
 **/\r
 UINT16\r
 GetLineByWidth (\r
   IN      CHAR16                      *InputString,\r
   IN      UINT16                      LineWidth,\r
+  IN OUT  UINT16                      *GlyphWidth,\r
   IN OUT  UINTN                       *Index,\r
   OUT     CHAR16                      **OutputString\r
   )\r
 {\r
-  UINT16          Count;\r
-  UINT16          Count2;\r
+  UINT16          StrOffset;\r
+  UINT16          GlyphOffset;\r
+  UINT16          OriginalGlyphWidth;\r
+  BOOLEAN         ReturnFlag;\r
+  UINT16          LastSpaceOffset;\r
+  UINT16          LastGlyphWidth;\r
+\r
+  if (InputString == NULL || Index == NULL || OutputString == NULL) {\r
+    return 0;\r
+  }\r
 \r
-  if (GetLineByWidthFinished) {\r
-    GetLineByWidthFinished = FALSE;\r
-    return (UINT16) 0;\r
+  if (LineWidth == 0 || *GlyphWidth == 0) {\r
+    return 0;\r
   }\r
 \r
-  Count         = LineWidth;\r
-  Count2        = 0;\r
+  //\r
+  // Save original glyph width.\r
+  //\r
+  OriginalGlyphWidth = *GlyphWidth;\r
+  LastGlyphWidth     = OriginalGlyphWidth;\r
+  ReturnFlag         = FALSE;\r
+  LastSpaceOffset    = 0;\r
 \r
-  *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
+  //\r
+  // NARROW_CHAR can not be printed in screen, so if a line only contain  the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line  in Screen.\r
+  // To avoid displaying this  empty line in screen,  just skip  the two CHARs here.\r
+  //\r
+  if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
+    *Index = *Index + 2;\r
+  }\r
 \r
   //\r
-  // Ensure we have got a valid buffer\r
+  // Fast-forward the string and see if there is a carriage-return in the string\r
   //\r
-  if (*OutputString != NULL) {\r
+  for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {\r
+    switch (InputString[*Index + StrOffset]) {\r
+      case NARROW_CHAR:\r
+        *GlyphWidth = 1;\r
+        break;\r
 \r
-    //\r
-    //NARROW_CHAR can not be printed in screen, so if a line only contain  the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line  in Screen.\r
-    //To avoid displaying this  empty line in screen,  just skip  the two CHARs here.\r
-    //\r
-   if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
-     *Index = *Index + 2;\r
-   }\r
+      case WIDE_CHAR:\r
+        *GlyphWidth = 2;\r
+        break;\r
 \r
-    //\r
-    // Fast-forward the string and see if there is a carriage-return in the string\r
-    //\r
-    for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
-      ;\r
+      case CHAR_CARRIAGE_RETURN:\r
+      case CHAR_LINEFEED:\r
+      case CHAR_NULL:\r
+        ReturnFlag = TRUE;\r
+        break;\r
 \r
+      default:\r
+        GlyphOffset = GlyphOffset + *GlyphWidth;\r
+\r
+        //\r
+        // Record the last space info in this line. Will be used in rewind.\r
+        //\r
+        if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {\r
+          LastSpaceOffset = StrOffset;\r
+          LastGlyphWidth  = *GlyphWidth;\r
+        }\r
+        break;\r
+    }\r
+\r
+    if (ReturnFlag) {\r
+      break;\r
+    }\r
+  } \r
+\r
+  //\r
+  // Rewind the string from the maximum size until we see a space to break the line\r
+  //\r
+  if (GlyphOffset > LineWidth) {\r
     //\r
-    // Copy the desired LineWidth of data to the output buffer.\r
-    // Also make sure that we don't copy more than the string.\r
-    // Also make sure that if there are linefeeds, we account for them.\r
+    // Rewind the string to last space char in this line.\r
     //\r
-    if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
-        (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
-        ) {\r
+    if (LastSpaceOffset != 0) {\r
+      StrOffset   = LastSpaceOffset;\r
+      *GlyphWidth = LastGlyphWidth;\r
+    } else {\r
       //\r
-      // Convert to CHAR16 value and show that we are done with this operation\r
+      // Roll back to last char in the line width.\r
       //\r
-      LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
-      if (LineWidth != 0) {\r
-        GetLineByWidthFinished = TRUE;\r
-      }\r
-    } else {\r
-      if (Count2 == LineWidth) {\r
-        //\r
-        // Rewind the string from the maximum size until we see a space to break the line\r
-        //\r
-        for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
-          ;\r
-        if (LineWidth == 0) {\r
-          LineWidth = Count;\r
-        }\r
-      } else {\r
-        LineWidth = Count2;\r
-      }\r
+      StrOffset--;\r
     }\r
+  }\r
+\r
+  //\r
+  // The CHAR_NULL has process last time, this time just return 0 to stand for the end.\r
+  //\r
+  if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Need extra glyph info and '\0' info, so +2.\r
+  //\r
+  *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));\r
+  if (*OutputString == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Save the glyph info at the begin of the string, will used by Print function.\r
+  //\r
+  if (OriginalGlyphWidth == 1) {\r
+    *(*OutputString) = NARROW_CHAR;\r
+  } else  {\r
+    *(*OutputString) = WIDE_CHAR;\r
+  }\r
 \r
-    CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
+  CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));\r
 \r
+  if (InputString[*Index + StrOffset] == CHAR_SPACE) {\r
+    //\r
+    // Skip the space info at the begin of next line.\r
+    //  \r
+    *Index = (UINT16) (*Index + StrOffset + 1);\r
+  } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
+    //\r
+    // Skip the /n or /n/r info.\r
     //\r
-    // If currently pointing to a space, increment the index to the first non-space character\r
+    if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
+  } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
     //\r
-    for (;\r
-         (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
-         (*Index)++\r
-        )\r
-      ;\r
-    *Index = (UINT16) (*Index + LineWidth);\r
-    return LineWidth;\r
+    // Skip the /r or /r/n info.\r
+    //  \r
+    if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
   } else {\r
-    return (UINT16) 0;\r
+    *Index = (UINT16) (*Index + StrOffset);\r
   }\r
+\r
+  //\r
+  // Include extra glyph info and '\0' info, so +2.\r
+  //\r
+  return StrOffset + 2;\r
 }\r
 \r
 \r
@@ -1423,38 +1506,38 @@ UpdateOptionSkipLines (
   UINTN   OriginalRow;\r
   CHAR16  *OutputString;\r
   CHAR16  *OptionString;\r
+  UINT16  GlyphWidth;\r
 \r
   Row           = 0;\r
   OptionString  = NULL;\r
+  Width         = (UINT16) gOptionBlockWidth;\r
+  OriginalRow   = 0;\r
+  GlyphWidth    = 1;\r
+  \r
   ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+  if (OptionString == NULL) {\r
+    return;\r
+  }\r
 \r
-  if (OptionString != NULL) {\r
-    Width               = (UINT16) gOptionBlockWidth;\r
-\r
-    OriginalRow         = Row;\r
-\r
-    for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+  for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &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 (&OptionString[Index]) != 0) {\r
+      Row++;\r
       //\r
-      // If there is more string to process print on the next row and increment the Skip value\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 (StrLen (&OptionString[Index]) != 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
+      // 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
-      FreePool (OutputString);\r
     }\r
 \r
-    Row = OriginalRow;\r
+    FreePool (OutputString);\r
   }\r
 \r
   if (OptionString != NULL) {\r
@@ -1530,6 +1613,10 @@ ValueIsScroll (
 \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
+\r
 **/\r
 INTN\r
 MoveToNextStatement (\r
@@ -1550,41 +1637,56 @@ MoveToNextStatement (
 \r
   while (TRUE) {\r
     NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+    //\r
+    // NextMenuOption->Row == 0 means this menu has not calculate\r
+    // the NextMenuOption->Skip value yet, just calculate here.\r
+    //\r
     if (NextMenuOption->Row == 0) {\r
       UpdateOptionSkipLines (Selection, NextMenuOption);\r
     }\r
     \r
     if (GoUp && (PreMenuOption != NextMenuOption)) {\r
       //\r
-      // Current Position doesn't need to be caculated when go up.\r
-      // Caculate distanct at first when go up\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
     }\r
+\r
     if (IsSelectable (NextMenuOption)) {\r
       break;\r
     }\r
+\r
+    //\r
+    // Arrive at begin of the menu list.\r
+    //\r
     if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
-      //\r
-      // Arrive at top.\r
-      //\r
       Distance = -1;\r
       break;\r
     }\r
+\r
     if (!GoUp) {\r
       //\r
-      // Caculate distanct at later when go down\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
   }\r
@@ -1891,13 +1993,7 @@ ProcessGotoOpCode (
   )\r
 {\r
   CHAR16                          *StringPtr;\r
-  UINTN                           StringLen;\r
-  UINTN                           BufferSize;\r
   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
-  CHAR16                          TemStr[2];\r
-  UINT8                           *DevicePathBuffer;\r
-  UINTN                           Index;\r
-  UINT8                           DigitUint8;\r
   FORM_BROWSER_FORM               *RefForm;\r
   EFI_INPUT_KEY                   Key;\r
   EFI_STATUS                      Status;\r
@@ -1907,57 +2003,47 @@ ProcessGotoOpCode (
   Status = EFI_SUCCESS;\r
   UpdateFormInfo = TRUE;\r
   StringPtr = NULL;\r
-  StringLen = 0;\r
 \r
   //\r
   // Prepare the device path check, get the device path info first.\r
   //\r
   if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
     StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
-    if (StringPtr != NULL) {\r
-      StringLen = StrLen (StringPtr);\r
-    }\r
   }\r
 \r
   //\r
   // Check whether the device path string is a valid string.\r
   //\r
-  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringLen != 0) {\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
     if (Selection->Form->ModalForm) {\r
       return Status;\r
     }\r
-    //\r
-    // Goto another Hii Package list\r
-    //\r
-    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-    BufferSize = StrLen (StringPtr) / 2;\r
-    DevicePath = AllocatePool (BufferSize);\r
-    ASSERT (DevicePath != NULL);\r
 \r
     //\r
-    // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
+    // Goto another Hii Package list\r
     //\r
-    DevicePathBuffer = (UINT8 *) DevicePath;\r
-    for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
-      TemStr[0] = StringPtr[Index];\r
-      DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
-      if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
-        //\r
-        // Invalid Hex Char as the tail.\r
-        //\r
-        break;\r
+    if (mPathFromText != NULL) {\r
+      DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+      if (DevicePath != NULL) {\r
+        Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+        FreePool (DevicePath);\r
       }\r
-      if ((Index & 1) == 0) {\r
-        DevicePathBuffer [Index/2] = DigitUint8;\r
-      } else {\r
-        DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
+      FreePool (StringPtr);\r
+    } else {\r
+      //\r
+      // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+      //\r
+      do {\r
+        CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gProtocolNotFound, gPressEnter, gEmptyString);\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      if (Repaint != NULL) {\r
+        *Repaint = TRUE;\r
       }\r
+      FreePool (StringPtr);\r
+      return Status;\r
     }\r
-    FreePool (StringPtr);\r
-\r
-    Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
-    FreePool (DevicePath);\r
 \r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
     if (Selection->Handle == NULL) {\r
       //\r
       // If target Hii Handle not found, exit\r
@@ -1999,12 +2085,7 @@ ProcessGotoOpCode (
     RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
 \r
     if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
-      Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      if (RefForm->SuppressExpression->Result.Value.b) {\r
+      if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
         //\r
         // Form is suppressed. \r
         //\r
@@ -2079,7 +2160,6 @@ UiDisplayMenu (
 {\r
   INTN                            SkipValue;\r
   INTN                            Difference;\r
-  INTN                            OldSkipValue;\r
   UINTN                           DistanceValue;\r
   UINTN                           Row;\r
   UINTN                           Col;\r
@@ -2093,7 +2173,9 @@ UiDisplayMenu (
   CHAR16                          *StringPtr;\r
   CHAR16                          *OptionString;\r
   CHAR16                          *OutputString;\r
-  CHAR16                          *FormattedString;\r
+  CHAR16                          *HelpString;\r
+  CHAR16                          *HelpHeaderString;\r
+  CHAR16                          *HelpBottomString;\r
   BOOLEAN                         NewLine;\r
   BOOLEAN                         Repaint;\r
   BOOLEAN                         SavedValue;\r
@@ -2121,22 +2203,43 @@ UiDisplayMenu (
   UI_MENU_LIST                    *CurrentMenu;\r
   UINTN                           ModalSkipColumn;\r
   BROWSER_HOT_KEY                 *HotKey;\r
+  UINTN                           HelpPageIndex;\r
+  UINTN                           HelpPageCount;\r
+  UINTN                           RowCount;\r
+  UINTN                           HelpLine;\r
+  UINTN                           HelpHeaderLine;\r
+  UINTN                           HelpBottomLine;\r
+  BOOLEAN                         MultiHelpPage;\r
+  UINT16                          GlyphWidth;\r
+  UINT16                          EachLineWidth;\r
+  UINT16                          HeaderLineWidth;\r
+  UINT16                          BottomLineWidth;\r
 \r
   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
 \r
   Status              = EFI_SUCCESS;\r
-  FormattedString     = NULL;\r
+  HelpString          = NULL;\r
+  HelpHeaderString    = NULL;\r
+  HelpBottomString    = NULL;\r
   OptionString        = NULL;\r
   ScreenOperation     = UiNoOperation;\r
   NewLine             = TRUE;\r
   MinRefreshInterval  = 0;\r
   DefaultId           = 0;\r
-\r
+  HelpPageCount       = 0;\r
+  HelpLine            = 0;\r
+  RowCount            = 0;\r
+  HelpBottomLine      = 0;\r
+  HelpHeaderLine      = 0;\r
+  HelpPageIndex       = 0;\r
+  MultiHelpPage       = FALSE;\r
+  EachLineWidth       = 0;\r
+  HeaderLineWidth     = 0;\r
+  BottomLineWidth     = 0;\r
   OutputString        = NULL;\r
   UpArrow             = FALSE;\r
   DownArrow           = FALSE;\r
   SkipValue           = 0;\r
-  OldSkipValue        = 0;\r
   MenuRefreshEntry    = gMenuRefreshHead;\r
 \r
   NextMenuOption      = NULL;\r
@@ -2237,6 +2340,9 @@ UiDisplayMenu (
         Temp            = (UINTN) SkipValue;\r
         Temp2           = (UINTN) SkipValue;\r
 \r
+        //\r
+        // 1. Clear the screen.\r
+        //\r
         if (Selection->Form->ModalForm) {\r
           ClearLines (\r
             LocalScreen.LeftColumn + ModalSkipColumn,\r
@@ -2257,6 +2363,9 @@ UiDisplayMenu (
         UiFreeRefreshList ();\r
         MinRefreshInterval = 0;\r
 \r
+        //\r
+        // 2.Paint the menu.\r
+        //\r
         for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
           MenuOption          = MENU_OPTION_FROM_LINK (Link);\r
           MenuOption->Row     = Row;\r
@@ -2282,6 +2391,7 @@ UiDisplayMenu (
 \r
           Width       = GetWidth (Statement, MenuOption->Handle);\r
           OriginalRow = Row;\r
+          GlyphWidth  = 1;\r
 \r
           if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
             //\r
@@ -2295,7 +2405,13 @@ UiDisplayMenu (
               );\r
           }\r
 \r
-          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+          //\r
+          // 2.1. Paint the description.\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
@@ -2317,6 +2433,9 @@ UiDisplayMenu (
           Temp  = 0;\r
           Row   = OriginalRow;\r
 \r
+          //\r
+          // 2.2. Paint the option string.\r
+          //\r
           Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
           if (EFI_ERROR (Status)) {\r
             //\r
@@ -2335,8 +2454,9 @@ UiDisplayMenu (
 \r
             Width       = (UINT16) gOptionBlockWidth;\r
             OriginalRow = Row;\r
+            GlyphWidth  = 1;\r
 \r
-            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\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
@@ -2372,7 +2492,7 @@ UiDisplayMenu (
           }\r
 \r
           //\r
-          // If Question has refresh guid, register the op-code.\r
+          // 2.4 Special process for Test opcode with test two.\r
           //\r
           if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
             if (gMenuEventGuidRefreshHead == NULL) {\r
@@ -2443,8 +2563,9 @@ UiDisplayMenu (
 \r
             Width       = (UINT16) gOptionBlockWidth;\r
             OriginalRow = Row;\r
+            GlyphWidth = 1;\r
 \r
-            for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
+            for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
               if ((Temp == 0) && (Row <= BottomRow)) {\r
                 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
               }\r
@@ -2479,11 +2600,10 @@ UiDisplayMenu (
           gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
 \r
           //\r
-          // Need to handle the bottom of the display\r
+          // 3. Update the row info which will be used by next menu.\r
           //\r
-          if (MenuOption->Skip > 1) {\r
+          if (Link == TopOfScreen) {\r
             Row += MenuOption->Skip - SkipValue;\r
-            SkipValue = 0;\r
           } else {\r
             Row += MenuOption->Skip;\r
           }\r
@@ -2535,6 +2655,16 @@ UiDisplayMenu (
       // NewPos:     Current menu option that need to hilight\r
       //\r
       ControlFlag = CfUpdateHelpString;\r
+      if (TopOfScreen == &MenuOption->Link) {\r
+        Temp = SkipValue;\r
+      } else {\r
+        Temp = 0;\r
+      }\r
+      if (NewPos == TopOfScreen) {\r
+        Temp2 = SkipValue;\r
+      } else {\r
+        Temp2 = 0;\r
+      }\r
       if (InitializedFlag) {\r
         InitializedFlag = FALSE;\r
         MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
@@ -2567,7 +2697,7 @@ UiDisplayMenu (
             SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
             Index += SavedMenuOption->Skip;\r
             if (Link == TopOfScreen) {\r
-              Index -= OldSkipValue;\r
+              Index -= SkipValue;\r
             }\r
             Link = Link->ForwardLink;\r
           }\r
@@ -2575,7 +2705,18 @@ UiDisplayMenu (
             SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
           }\r
 \r
-          if (Link != NewPos || Index > BottomRow || (Link == NewPos && SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow)) {\r
+          //\r
+          // Not find the selected menu in current show page.\r
+          // Have two case to enter this if:\r
+          // 1. Not find the menu at current page.\r
+          // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
+          //    For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
+          //\r
+          // Base on the selected menu will show at the bottom of the page,\r
+          // select the menu which will show at the top of the page.\r
+          //\r
+          if (Link != NewPos || Index > BottomRow || \r
+              (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\r
             //\r
             // Find the MenuOption which has the skip value for Date/Time opcode. \r
             //\r
@@ -2590,7 +2731,11 @@ UiDisplayMenu (
             if (SavedMenuOption->Row == 0) {\r
               UpdateOptionSkipLines (Selection, SavedMenuOption);\r
             }\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 <= BottomRow + 1; ) {            \r
               Link = Link->BackLink;\r
@@ -2598,16 +2743,29 @@ UiDisplayMenu (
               if (SavedMenuOption->Row == 0) {\r
                 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
               }\r
-              Index     += SavedMenuOption->Skip;\r
+              Index += SavedMenuOption->Skip;\r
             }\r
-            \r
-            SkipValue = Index - BottomRow - 1;\r
-            if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
-              TopOfScreen     = Link;\r
-              OldSkipValue    = SkipValue;\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
             } else {\r
-              SkipValue       = 0;\r
-              TopOfScreen     = Link->ForwardLink;\r
+              //\r
+              // Check whether need to skip some line for menu shows at the top of the page.\r
+              //\r
+              SkipValue = Index - BottomRow - 1;\r
+              if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen     = Link;\r
+              } else {\r
+                SkipValue       = 0;\r
+                TopOfScreen     = Link->ForwardLink;\r
+              }\r
             }\r
 \r
             Repaint = TRUE;\r
@@ -2642,19 +2800,25 @@ UiDisplayMenu (
 \r
             Width               = (UINT16) gOptionBlockWidth;\r
             OriginalRow         = MenuOption->Row;\r
+            GlyphWidth          = 1;\r
 \r
-            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
-              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
-                MenuOption->Row++;\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
@@ -2670,19 +2834,25 @@ UiDisplayMenu (
 \r
               OriginalRow = MenuOption->Row;\r
               Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+              GlyphWidth  = 1;\r
 \r
-              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
-                if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
-                  MenuOption->Row++;\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
@@ -2741,19 +2911,25 @@ UiDisplayMenu (
           Width               = (UINT16) gOptionBlockWidth;\r
 \r
           OriginalRow         = MenuOption->Row;\r
+          GlyphWidth          = 1;\r
 \r
-          for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
-            if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
@@ -2764,19 +2940,25 @@ UiDisplayMenu (
             OriginalRow = MenuOption->Row;\r
 \r
             Width       = GetWidth (Statement, MenuOption->Handle);\r
+            GlyphWidth          = 1;\r
 \r
-            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
-              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
-                MenuOption->Row++;\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
@@ -2815,22 +2997,125 @@ UiDisplayMenu (
           StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
         }\r
 \r
-        ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
-\r
-        gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
-\r
-        for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
+        RowCount      = BottomRow - TopRow;\r
+        HelpPageIndex = 0;\r
+        //\r
+        // 1.Calculate how many line the help string need to print.\r
+        //\r
+        if (HelpString != NULL) {\r
+          FreePool (HelpString);\r
+        }\r
+        HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);\r
+        if (HelpLine > RowCount) {\r
+          MultiHelpPage   = TRUE;\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
+          if (HelpHeaderString != NULL) {\r
+            FreePool (HelpHeaderString);\r
+          }\r
+          HelpHeaderLine  = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, RowCount);\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
+          if (HelpBottomString != NULL) {\r
+            FreePool (HelpBottomString);\r
+          }\r
+          HelpBottomLine  = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, RowCount);\r
           //\r
-          // Pad String with spaces to simulate a clearing of the previous line\r
+          // Calculate the help page count.\r
           //\r
-          for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
-            StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
+          if (HelpLine > 2 * RowCount - 2) {\r
+            HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
+            if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
+              HelpPageCount += 1;\r
+            }\r
+          } else {\r
+            HelpPageCount = 2;\r
           }\r
+        } else {\r
+          MultiHelpPage = FALSE;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Clean the help field first.\r
+      //\r
+      ClearLines (\r
+        LocalScreen.RightColumn - gHelpBlockWidth,\r
+        LocalScreen.RightColumn,\r
+        TopRow,\r
+        BottomRow,\r
+        PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+        );\r
 \r
+      //\r
+      // Check whether need to show the 'More(U/u)' at the begin.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex > 0) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+        for (Index = 0; Index < HelpHeaderLine; Index++) {\r
+          ASSERT (HelpHeaderLine == 1);\r
+          ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
+            Index + TopRow,\r
+            &HelpHeaderString[Index * HeaderLineWidth]\r
+            );\r
+        }\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
+      //\r
+      // Print the help string info.\r
+      //\r
+      if (!MultiHelpPage) {\r
+        for (Index = 0; Index < HelpLine; Index++) {\r
           PrintStringAt (\r
             LocalScreen.RightColumn - gHelpBlockWidth,\r
             Index + TopRow,\r
-            &FormattedString[Index * gHelpBlockWidth * 2]\r
+            &HelpString[Index * EachLineWidth]\r
+            );\r
+        }\r
+        gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+      } else  {\r
+        if (HelpPageIndex == 0) {\r
+          for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
+            PrintStringAt (\r
+              LocalScreen.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow,\r
+              &HelpString[Index * EachLineWidth]\r
+              );\r
+          }\r
+        } else {\r
+          for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
+              (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
+            PrintStringAt (\r
+              LocalScreen.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow + HelpHeaderLine,\r
+              &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth]\r
+              );\r
+          }\r
+          if (HelpPageIndex == HelpPageCount - 1) {\r
+            gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+          }\r
+        } \r
+      }\r
+\r
+      //\r
+      // Check whether need to print the 'More(D/d)' at the bottom.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+        for (Index = 0; Index < HelpBottomLine; Index++) {\r
+          ASSERT (HelpBottomLine == 1);\r
+          ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
+            Index + BottomRow - HelpBottomLine,\r
+            &HelpBottomString[Index * BottomLineWidth]\r
             );\r
         }\r
       }\r
@@ -2852,30 +3137,43 @@ UiDisplayMenu (
       //\r
       // Wait for user's selection\r
       //\r
-      do {\r
-        Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
-      } while (Status == EFI_TIMEOUT);\r
+      while (TRUE) {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        if (!EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
 \r
-      if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
         //\r
-        // IFR is updated in Callback of refresh opcode, re-parse it\r
+        // If we encounter error, continue to read another key in.\r
         //\r
-        ControlFlag = CfCheckSelection;\r
-        Selection->Statement = NULL;\r
-        break;\r
+        if (Status != EFI_NOT_READY) {\r
+          continue;\r
+        }\r
+\r
+        Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
+          //\r
+          // IFR is updated in Callback of refresh opcode, re-parse it\r
+          //\r
+          ControlFlag = CfCheckSelection;\r
+          Selection->Statement = NULL;\r
+          break;\r
+        }\r
       }\r
 \r
-      Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-      //\r
-      // If we encounter error, continue to read another key in.\r
-      //\r
-      if (EFI_ERROR (Status)) {\r
-        ControlFlag = CfReadKey;\r
+      if (ControlFlag == CfCheckSelection) {\r
         break;\r
       }\r
 \r
       switch (Key.UnicodeChar) {\r
       case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
         ScreenOperation = UiSelect;\r
         gDirection      = 0;\r
         break;\r
@@ -2890,7 +3188,7 @@ 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
-        if(IsListEmpty (&gMenuOption)) {\r
+        if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
@@ -2943,12 +3241,32 @@ UiDisplayMenu (
           }\r
           \r
           ASSERT(MenuOption != NULL);\r
-          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
             ScreenOperation = UiSelect;\r
           }\r
         }\r
         break;\r
 \r
+      case 'D':\r
+      case 'd':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
+        break;\r
+\r
+      case 'U':\r
+      case 'u':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
+        break;\r
+\r
       case CHAR_NULL:\r
         for (Index = 0; Index < mScanCodeNumber; Index++) {\r
           if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
@@ -2967,7 +3285,8 @@ UiDisplayMenu (
           // Check whether Key matches the registered hot key.\r
           //\r
           HotKey = NULL;\r
-          if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
+          if ((gBrowserSettingScope == SystemLevel) || \r
+              (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
             HotKey = GetHotKeyFromRegisterList (&Key);\r
           }\r
           if (HotKey != NULL) {\r
@@ -3155,7 +3474,6 @@ UiDisplayMenu (
           TopOfScreen = NewPos;\r
           Repaint     = TRUE;\r
           SkipValue = 0;\r
-          OldSkipValue = 0;\r
         } else if (!IsSelectable (NextMenuOption)) {\r
           //\r
           // Continue to go up until scroll to next page or the selectable option is found.\r
@@ -3184,9 +3502,15 @@ UiDisplayMenu (
       break;\r
 \r
     case CfUiPageUp:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
       ControlFlag     = CfCheckSelection;\r
 \r
       ASSERT(NewPos != NULL);\r
+      //\r
+      // Already at the first menu option, so do nothing.\r
+      //\r
       if (NewPos->BackLink == &gMenuOption) {\r
         NewLine = FALSE;\r
         Repaint = FALSE;\r
@@ -3195,8 +3519,22 @@ UiDisplayMenu (
 \r
       NewLine   = TRUE;\r
       Repaint   = TRUE;\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
+      if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {\r
+        SkipValue -= BottomRow - TopRow + 1;\r
+        break;\r
+      }\r
+\r
       Link      = TopOfScreen;\r
-      Index     = BottomRow;\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
@@ -3204,13 +3542,13 @@ UiDisplayMenu (
           UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
         }        \r
         if (Index < PreviousMenuOption->Skip) {\r
-          Index = 0;\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
@@ -3229,10 +3567,13 @@ UiDisplayMenu (
           MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
         }\r
       } else {\r
-        if (Index + 1 < TopRow) {\r
+        if (Index >= TopRow) {\r
           //\r
-          // Back up the previous option.\r
+          // At here, only case "Index < PreviousMenuOption->Skip" can reach here.\r
           //\r
+          SkipValue = PreviousMenuOption->Skip - (Index - TopRow);\r
+        } else {\r
+          SkipValue = PreviousMenuOption->Skip - (TopRow - Index);\r
           Link = Link->ForwardLink;\r
         }\r
 \r
@@ -3263,6 +3604,9 @@ UiDisplayMenu (
       break;\r
 \r
     case CfUiPageDown:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
       ControlFlag     = CfCheckSelection;\r
 \r
       ASSERT (NewPos != NULL);\r
@@ -3276,47 +3620,62 @@ UiDisplayMenu (
       Repaint = TRUE;\r
       Link    = TopOfScreen;\r
       NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-      Index = TopRow;\r
-      while ((Index <= BottomRow) && (Link->ForwardLink != &gMenuOption)) {\r
-        Index = Index + NextMenuOption->Skip;\r
+      Index = TopRow + NextMenuOption->Skip - SkipValue;\r
+      //\r
+      // Count to the menu option which will show at the top of the next form.\r
+      //\r
+      while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {\r
         Link           = Link->ForwardLink;\r
         NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        Index = Index + NextMenuOption->Skip;\r
       }\r
 \r
-      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
         //\r
         // Finally we know that NewPos is the last MenuOption can be focused.\r
         //\r
         Repaint = FALSE;\r
         MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
+        SkipValue = 0;\r
       } else {\r
-        if (Index - 1 > BottomRow) {\r
+        //\r
+        // Calculate the skip line for top of screen menu.\r
+        //\r
+        if (Link == TopOfScreen) {\r
           //\r
-          // Back up the previous option.\r
+          // The top of screen menu option occupies the entire form.\r
           //\r
-          Link = Link->BackLink;\r
+          SkipValue += BottomRow - TopRow + 1;\r
+        } else {\r
+          SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
         }\r
-        //\r
-        // There are more MenuOption needing scrolling down.\r
-        //\r
+\r
         TopOfScreen = Link;\r
         MenuOption = NULL;\r
         //\r
-        // Move to the option in Next page.\r
+        // Move to the Next selectable menu.\r
         //\r
         MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
       }\r
 \r
+      //\r
+      // Save the menu as the next highlight menu.\r
+      //\r
+      NewPos  = Link;\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
       //\r
-      NewPos  = Link;\r
       AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
       AdjustDateAndTimePosition (TRUE, &NewPos);\r
       break;\r
 \r
     case CfUiDown:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      // NewPos  points to the menu which is highlighted now.\r
+      //\r
       ControlFlag = CfCheckSelection;\r
       //\r
       // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
@@ -3335,8 +3694,14 @@ UiDisplayMenu (
         NewPos          = NewPos->ForwardLink;\r
 \r
         Difference      = 0;\r
+        //\r
+        // Current menu not at the bottom of the form.\r
+        //\r
         if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
-          Difference    = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
+          //\r
+          // Find the next selectable menu.\r
+          //\r
+          Difference = MoveToNextStatement (Selection, 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
@@ -3354,7 +3719,8 @@ UiDisplayMenu (
             }\r
             NewPos        = gMenuOption.ForwardLink;\r
             MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
-    \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
@@ -3364,11 +3730,9 @@ UiDisplayMenu (
           }\r
         }\r
         NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
-\r
-        //\r
-        // An option might be multi-line, so we need to reflect that data in the overall skip value\r
-        //\r
-        UpdateOptionSkipLines (Selection, NextMenuOption);\r
+        if (NextMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, NextMenuOption);\r
+        }\r
         DistanceValue  = Difference + NextMenuOption->Skip;\r
 \r
         Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
@@ -3393,18 +3757,16 @@ UiDisplayMenu (
             //\r
             // If bottom op-code is more than one line or top op-code is more than one line\r
             //\r
-            if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {\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 - OldSkipValue)) {\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 - OldSkipValue);\r
-\r
-                OldSkipValue    = Difference;\r
+                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
 \r
                 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
 \r
@@ -3424,20 +3786,17 @@ UiDisplayMenu (
                 // SkipValue, set the skips to one less than what is required.\r
                 //\r
                 SkipValue = Difference - 1;\r
-\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 = OldSkipValue + (Temp - BottomRow) - 1;\r
+                SkipValue += (Temp - BottomRow) - 1;\r
               }\r
             } else {\r
-              if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+              if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
                 TopOfScreen = TopOfScreen->ForwardLink;\r
                 break;\r
-              } else {\r
-                SkipValue = OldSkipValue;\r
               }\r
             }\r
             //\r
@@ -3459,7 +3818,6 @@ UiDisplayMenu (
           } while (SavedMenuOption->Skip == 0);\r
 \r
           Repaint       = TRUE;\r
-          OldSkipValue  = SkipValue;\r
         } else if (!IsSelectable (NextMenuOption)) {\r
           //\r
           // Continue to go down until scroll to next page or the selectable option is found.\r
@@ -3481,9 +3839,18 @@ UiDisplayMenu (
           Repaint     = TRUE;\r
           MenuOption  = NULL;\r
         } else {\r
+          //\r
+          // Need to remove the current highlight menu.\r
+          // MenuOption saved the last highlight menu info.\r
+          //\r
           MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
         }\r
+\r
+        SkipValue     = 0;\r
         NewLine       = TRUE;\r
+        //\r
+        // Get the next highlight menu.\r
+        //\r
         NewPos        = gMenuOption.ForwardLink;\r
         MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
       }\r
@@ -3526,7 +3893,7 @@ UiDisplayMenu (
       // Reterieve default setting. After it. NV flag will be showed.\r
       //\r
       if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
-        Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope);\r
+        Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
         if (!EFI_ERROR (Status)) {\r
           Selection->Action = UI_ACTION_REFRESH_FORM;\r
           Selection->Statement = NULL;\r
@@ -3604,7 +3971,7 @@ UiDisplayMenu (
       //\r
       // Reset to default value for all forms in the whole system.\r
       //\r
-      Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel);\r
+      Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);\r
 \r
       if (!EFI_ERROR (Status)) {\r
         Selection->Action = UI_ACTION_REFRESH_FORM;\r
@@ -3624,6 +3991,15 @@ UiDisplayMenu (
       gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
       gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
       gST->ConOut->OutputString (gST->ConOut, L"\n");\r
+      if (HelpString != NULL) {\r
+        FreePool (HelpString);\r
+      }\r
+      if (HelpHeaderString != NULL) {\r
+        FreePool (HelpHeaderString);\r
+      }\r
+      if (HelpBottomString != NULL) {\r
+        FreePool (HelpBottomString);\r
+      }\r
 \r
       return EFI_SUCCESS;\r
 \r