]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Add new call back return value; also add some sample code to use it.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index 8ed2c00a70552ae1d0b1a486cd84ac2225e118bb..d5f726b0cefec550c26612fa2e09618b9c58565c 100644 (file)
@@ -340,8 +340,6 @@ RefreshForm (
   EFI_STATUS                      Status;\r
   UI_MENU_SELECTION               *Selection;\r
   FORM_BROWSER_STATEMENT          *Question;\r
-  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
 \r
   if (gMenuRefreshHead != NULL) {\r
 \r
@@ -353,8 +351,6 @@ RefreshForm (
     mHiiPackageListUpdated = FALSE;\r
 \r
     do {\r
-      gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
-\r
       Selection = MenuRefreshEntry->Selection;\r
       Question = MenuRefreshEntry->MenuOption->ThisTag;\r
 \r
@@ -373,6 +369,22 @@ RefreshForm (
         for (Index = 0; OptionString[Index] == L' '; Index++)\r
           ;\r
 \r
+        //\r
+        // If old Text is longer than new string, need to clean the old string before paint the newer.\r
+        // This option is no need for time/date opcode, because time/data opcode has fixed string length.\r
+        //\r
+        if ((MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_DATE_OP) &&\r
+          (MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_TIME_OP)) {\r
+          ClearLines (\r
+            MenuRefreshEntry->CurrentColumn, \r
+            MenuRefreshEntry->CurrentColumn + gOptionBlockWidth - 1,\r
+            MenuRefreshEntry->CurrentRow,\r
+            MenuRefreshEntry->CurrentRow,\r
+            PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+            );\r
+        }\r
+\r
+        gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
         PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
         FreePool (OptionString);\r
       }\r
@@ -380,36 +392,9 @@ RefreshForm (
       //\r
       // Question value may be changed, need invoke its Callback()\r
       //\r
-      ConfigAccess = Selection->FormSet->ConfigAccess;\r
-      if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-        Status = ConfigAccess->Callback (\r
-                                 ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_CHANGING,\r
-                                 Question->QuestionId,\r
-                                 Question->HiiValue.Type,\r
-                                 &Question->HiiValue.Value,\r
-                                 &ActionRequest\r
-                                 );\r
-        if (!EFI_ERROR (Status)) {\r
-          switch (ActionRequest) {\r
-          case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-            gResetRequired = TRUE;\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-            SubmitForm (Selection->FormSet, Selection->Form);\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            gNvUpdateRequired = FALSE;\r
-            break;\r
-\r
-          default:\r
-            break;\r
-          }\r
-        }\r
+      Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
       }\r
 \r
       MenuRefreshEntry = MenuRefreshEntry->Next;\r
@@ -616,6 +601,15 @@ UiAddMenuOption (
       MenuOption->IsQuestion = TRUE;\r
       break;\r
 \r
+    case EFI_IFR_TEXT_OP:\r
+      if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {\r
+        //\r
+        // Initializing GrayOut option as TRUE for Text setup options \r
+        // so that those options will be Gray in colour and un selectable.\r
+        //\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+\r
     default:\r
       MenuOption->IsQuestion = FALSE;\r
       break;\r
@@ -981,6 +975,7 @@ CreateMultiStringPopUp (
 /**\r
   Update status bar on the bottom of menu.\r
 \r
+  @param  Selection              Current Selction info.\r
   @param  MessageType            The type of message to be shown.\r
   @param  Flags                  The flags in Question header.\r
   @param  State                  Set or clear.\r
@@ -988,6 +983,7 @@ CreateMultiStringPopUp (
 **/\r
 VOID\r
 UpdateStatusBar (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
   IN  UINTN                       MessageType,\r
   IN  UINT8                       Flags,\r
   IN  BOOLEAN                     State\r
@@ -1031,7 +1027,9 @@ UpdateStatusBar (
           );\r
         gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
 \r
-        gNvUpdateRequired = TRUE;\r
+        if (Selection != NULL) {\r
+          Selection->Form->NvUpdateRequired = TRUE;\r
+        }\r
       } else {\r
         gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
         for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
@@ -1042,18 +1040,20 @@ UpdateStatusBar (
             );\r
         }\r
 \r
-        gNvUpdateRequired = FALSE;\r
+        if (Selection != NULL) {\r
+          Selection->Form->NvUpdateRequired = FALSE;\r
+        }\r
       }\r
     }\r
     break;\r
 \r
   case REFRESH_STATUS_BAR:\r
     if (mInputError) {\r
-      UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
+      UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE);\r
     }\r
 \r
-    if (gNvUpdateRequired) {\r
-      UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
+    if (IsNvUpdateRequired(Selection->FormSet)) {\r
+      UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE);\r
     }\r
     break;\r
 \r
@@ -1332,7 +1332,6 @@ ValueIsScroll (
   )\r
 {\r
   LIST_ENTRY      *Temp;\r
-  UI_MENU_OPTION  *MenuOption;\r
 \r
   Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
 \r
@@ -1340,14 +1339,7 @@ ValueIsScroll (
     return TRUE;\r
   }\r
 \r
-  for (; Temp != &gMenuOption; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
-    MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
-    if (IsSelectable (MenuOption)) {\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  return TRUE;\r
+  return FALSE;\r
 }\r
 \r
 \r
@@ -1358,6 +1350,7 @@ ValueIsScroll (
 \r
   @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
   @param  CurrentPosition        Current position.\r
+  @param  GapToTop               Gap position to top or bottom.\r
 \r
   @return The row distance from current MenuOption to next selectable MenuOption.\r
 \r
@@ -1365,51 +1358,54 @@ ValueIsScroll (
 INTN\r
 MoveToNextStatement (\r
   IN     BOOLEAN                   GoUp,\r
-  IN OUT LIST_ENTRY                **CurrentPosition\r
+  IN OUT LIST_ENTRY                **CurrentPosition,\r
+  IN     UINTN                     GapToTop\r
   )\r
 {\r
   INTN             Distance;\r
   LIST_ENTRY       *Pos;\r
-  BOOLEAN          HitEnd;\r
   UI_MENU_OPTION   *NextMenuOption;\r
+  UI_MENU_OPTION   *PreMenuOption;\r
 \r
-  Distance = 0;\r
-  Pos      = *CurrentPosition;\r
-  HitEnd   = FALSE;\r
+  Distance      = 0;\r
+  Pos           = *CurrentPosition;\r
+  PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
 \r
   while (TRUE) {\r
     NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\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
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+      Distance += NextMenuOption->Skip;\r
+    }\r
     if (IsSelectable (NextMenuOption)) {\r
       break;\r
     }\r
     if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
-      HitEnd = TRUE;\r
+      //\r
+      // Arrive at top.\r
+      //\r
+      Distance = -1;\r
       break;\r
     }\r
-    Distance += NextMenuOption->Skip;\r
-    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
-  }\r
-\r
-  if (HitEnd) {\r
-    //\r
-    // If we hit end there is still no statement can be focused,\r
-    // we go backwards to find the statement can be focused.\r
-    //\r
-    Distance = 0;\r
-    Pos = *CurrentPosition;\r
-\r
-    while (TRUE) {\r
-      NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
-      if (IsSelectable (NextMenuOption)) {\r
-        break;\r
-      }\r
-      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
-        ASSERT (FALSE);\r
+    if (!GoUp) {\r
+      //\r
+      // Caculate distanct at later when go down\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
         break;\r
       }\r
-      Distance -= NextMenuOption->Skip;\r
-      Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+      Distance += NextMenuOption->Skip;\r
     }\r
+    PreMenuOption = NextMenuOption;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
   }\r
 \r
   *CurrentPosition = &NextMenuOption->Link;\r
@@ -1621,13 +1617,12 @@ UiDisplayMenu (
   CHAR16                          *OptionString;\r
   CHAR16                          *OutputString;\r
   CHAR16                          *FormattedString;\r
-  CHAR16                          YesResponse;\r
-  CHAR16                          NoResponse;\r
   BOOLEAN                         NewLine;\r
   BOOLEAN                         Repaint;\r
   BOOLEAN                         SavedValue;\r
   BOOLEAN                         UpArrow;\r
   BOOLEAN                         DownArrow;\r
+  BOOLEAN                         InitializedFlag;\r
   EFI_STATUS                      Status;\r
   EFI_INPUT_KEY                   Key;\r
   LIST_ENTRY                      *Link;\r
@@ -1710,6 +1705,7 @@ UiDisplayMenu (
     CurrentMenu = UiAddMenuList (NULL, &Selection->FormSetGuid, Selection->FormId);\r
   }\r
   ASSERT (CurrentMenu != NULL);\r
+  Selection->CurrentMenu = CurrentMenu;\r
 \r
   if (Selection->QuestionId == 0) {\r
     //\r
@@ -1719,12 +1715,13 @@ UiDisplayMenu (
   }\r
 \r
   //\r
-  // Get user's selection\r
+  // Init option as the current user's selection\r
   //\r
+  InitializedFlag = TRUE;\r
   NewPos = gMenuOption.ForwardLink;\r
 \r
   gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
-  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
+  UpdateStatusBar (Selection, REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
 \r
   ControlFlag = CfInitialization;\r
   Selection->Action = UI_ACTION_NONE;\r
@@ -1793,8 +1790,7 @@ UiDisplayMenu (
           Width       = GetWidth (Statement, MenuOption->Handle);\r
           OriginalRow = Row;\r
 \r
-          if (Statement->Operand == EFI_IFR_REF_OP && \r
-            MenuOption->Col >= 2) {\r
+          if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
             //\r
             // Print Arrow for Goto button.\r
             //\r
@@ -2042,6 +2038,10 @@ UiDisplayMenu (
       // NewPos:     Current menu option that need to hilight\r
       //\r
       ControlFlag = CfUpdateHelpString;\r
+      if (InitializedFlag) {\r
+        InitializedFlag = FALSE;\r
+        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+      }\r
 \r
       //\r
       // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
@@ -2175,22 +2175,17 @@ UiDisplayMenu (
         }\r
 \r
         //\r
-        // This is only possible if we entered this page and the first menu option is\r
-        // a "non-menu" item.  In that case, force it UiDown\r
+        // This is the current selected statement\r
         //\r
         MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        Statement = MenuOption->ThisTag;\r
+        Selection->Statement = Statement;\r
         if (!IsSelectable (MenuOption)) {\r
-          ASSERT (ScreenOperation == UiNoOperation);\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
+          Repaint = SavedValue;\r
+          UpdateKeyHelp (Selection, MenuOption, FALSE);\r
           break;\r
         }\r
 \r
-        //\r
-        // This is the current selected statement\r
-        //\r
-        Statement = MenuOption->ThisTag;\r
-        Selection->Statement = Statement;\r
         //\r
         // Record highlight for current menu\r
         //\r
@@ -2209,7 +2204,7 @@ UiDisplayMenu (
         //\r
         if (gMenuRefreshHead != NULL) {\r
           for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
-            if (MenuOption->GrayOut) {\r
+            if (MenuRefreshEntry->MenuOption->GrayOut) {\r
               MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
             } else {               \r
               MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
@@ -2299,12 +2294,12 @@ UiDisplayMenu (
     case CfUpdateHelpString:\r
       ControlFlag = CfPrepareToReadKey;\r
 \r
-        if (Repaint || NewLine) {\r
+      if (Repaint || NewLine) {\r
         //\r
         // Don't print anything if it is a NULL help token\r
         //\r
         ASSERT(MenuOption != NULL);\r
-        if (MenuOption->ThisTag->Help == 0) {\r
+        if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
           StringPtr = L"\0";\r
         } else {\r
           StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
@@ -2478,20 +2473,6 @@ UiDisplayMenu (
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
-        //\r
-        // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
-        //\r
-        for (Link = gMenuOption.ForwardLink; Link != &gMenuOption; Link = Link->ForwardLink) {\r
-          NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-          if (IsSelectable (NextMenuOption)) {\r
-            break;\r
-          }\r
-        }\r
-\r
-        if (Link == &gMenuOption) {\r
-          ControlFlag = CfPrepareToReadKey;\r
-          break;\r
-        }\r
       }\r
 \r
       for (Index = 0;\r
@@ -2692,84 +2673,10 @@ UiDisplayMenu (
       // We come here when someone press ESC\r
       //\r
       ControlFlag = CfCheckSelection;\r
-\r
-      if (CurrentMenu->Parent != NULL) {\r
-        //\r
-        // we have a parent, so go to the parent menu\r
-        //\r
-        if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
-          //\r
-          // The parent menu and current menu are in the same formset\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORM;\r
-        } else {\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-        }\r
-        Selection->Statement = NULL;\r
-\r
-        Selection->FormId = CurrentMenu->Parent->FormId;\r
-        Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
-\r
-        //\r
-        // Clear highlight record for this menu\r
-        //\r
-        CurrentMenu->QuestionId = 0;\r
-        break;\r
-      }\r
-\r
-      if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-        //\r
-        // We never exit FrontPage, so skip the ESC\r
-        //\r
-        Selection->Action = UI_ACTION_NONE;\r
-        break;\r
-      }\r
-\r
-      //\r
-      // We are going to leave current FormSet, so check uncommited data in this FormSet\r
-      //\r
-      if (gNvUpdateRequired) {\r
-        Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-        YesResponse = gYesResponse[0];\r
-        NoResponse  = gNoResponse[0];\r
-\r
-        //\r
-        // If NV flag is up, prompt user\r
-        //\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-        } while\r
-        (\r
-          (Key.ScanCode != SCAN_ESC) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-        );\r
-\r
-        if (Key.ScanCode == SCAN_ESC) {\r
-          //\r
-          // User hits the ESC key\r
-          //\r
-          Repaint = TRUE;\r
-          NewLine = TRUE;\r
-\r
-          Selection->Action = UI_ACTION_NONE;\r
-          break;\r
-        }\r
-\r
-        //\r
-        // If the user hits the YesResponse key\r
-        //\r
-        if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-          Status = SubmitForm (Selection->FormSet, Selection->Form);\r
-        }\r
-      }\r
-\r
-      Selection->Action = UI_ACTION_EXIT;\r
-      Selection->Statement = NULL;\r
-      CurrentMenu->QuestionId = 0;\r
-\r
-      return EFI_SUCCESS;\r
+      if (FindNextMenu (Selection, &Repaint, &NewLine)) {\r
+        return EFI_SUCCESS;\r
+      } \r
+      break;\r
 \r
     case CfUiLeft:\r
       ControlFlag = CfCheckSelection;\r
@@ -2802,47 +2709,47 @@ UiDisplayMenu (
     case CfUiUp:\r
       ControlFlag = CfCheckSelection;\r
 \r
-      SavedListEntry = TopOfScreen;\r
+      SavedListEntry = NewPos;\r
 \r
       ASSERT(NewPos != NULL);\r
+      //\r
+      // Adjust Date/Time position before we advance forward.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
       if (NewPos->BackLink != &gMenuOption) {\r
-        NewLine = TRUE;\r
-        //\r
-        // Adjust Date/Time position before we advance forward.\r
-        //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\r
-\r
-        //\r
-        // Caution that we have already rewind to the top, don't go backward in this situation.\r
-        //\r
-        if (NewPos->BackLink != &gMenuOption) {\r
-          NewPos = NewPos->BackLink;\r
-        }\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        NewLine    = TRUE;\r
+        NewPos     = NewPos->BackLink;\r
 \r
-        Difference = MoveToNextStatement (TRUE, &NewPos);\r
         PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
         DistanceValue = PreviousMenuOption->Skip;\r
-\r
-        //\r
-        // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
-        // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
-        // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
-        // checking can be done.\r
-        //\r
-        DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\r
-        \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
         ASSERT (MenuOption != NULL);\r
         if (Difference < 0) {\r
           //\r
-          // We want to goto previous MenuOption, but finally we go down.\r
-          // it means that we hit the begining MenuOption that can be focused\r
-          // so we simply scroll to the top\r
+          // We hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top.\r
           //\r
-          if (SavedListEntry != gMenuOption.ForwardLink) {\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 ((INTN) MenuOption->Row - (INTN) DistanceValue - Difference < (INTN) TopRow) {\r
+        } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
           //\r
           // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
           //\r
@@ -2850,27 +2757,30 @@ UiDisplayMenu (
           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
+          //\r
+          ScreenOperation = UiUp;\r
+          ControlFlag     = CfScreenOperation;\r
         }\r
 \r
         //\r
         // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
         //\r
         AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
-\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\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
       }\r
       break;\r
 \r
@@ -2887,38 +2797,59 @@ UiDisplayMenu (
       NewLine   = TRUE;\r
       Repaint   = TRUE;\r
       Link      = TopOfScreen;\r
-      PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-      Index = BottomRow;\r
+      Index     = BottomRow;\r
       while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
-        Index = Index - PreviousMenuOption->Skip;\r
         Link = Link->BackLink;\r
         PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\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
+        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 + 1 < TopRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->ForwardLink;\r
+        }\r
 \r
-      TopOfScreen = Link;\r
-      Difference = MoveToNextStatement (TRUE, &Link);\r
-      if (Difference > 0) {\r
         //\r
-        // The focus MenuOption is above the TopOfScreen\r
+        // Move to the option in Next page.\r
         //\r
-        TopOfScreen = Link;\r
-      } else if (Difference < 0) {\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
         //\r
-        // This happens when there is no MenuOption can be focused from\r
-        // Current MenuOption to the first MenuOption\r
+        // There are more MenuOption needing scrolling up.\r
         //\r
-        TopOfScreen = gMenuOption.ForwardLink;\r
-      }\r
-      Index += Difference;\r
-      if (Index < TopRow) {\r
-        MenuOption = NULL;\r
-      }\r
-\r
-      if (NewPos == Link) {\r
-        Repaint = FALSE;\r
-        NewLine = FALSE;\r
-      } else {\r
-        NewPos = Link;\r
+        TopOfScreen = Link;\r
+        MenuOption  = NULL;\r
       }\r
 \r
       //\r
@@ -2950,28 +2881,35 @@ UiDisplayMenu (
         NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       }\r
 \r
-      Index += MoveToNextStatement (FALSE, &Link);\r
-      if (Index > BottomRow) {\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
+        //\r
+        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        //\r
+        Repaint = FALSE;\r
+        MoveToNextStatement (TRUE, &Link, Index - TopRow);\r
+      } else {\r
+        if (Index - 1 > BottomRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->BackLink;\r
+        }\r
         //\r
-        // There are more MenuOption needing scrolling\r
+        // There are more MenuOption needing scrolling down.\r
         //\r
         TopOfScreen = Link;\r
         MenuOption = NULL;\r
-      }\r
-      if (NewPos == Link && Index <= BottomRow) {\r
         //\r
-        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        // Move to the option in Next page.\r
         //\r
-        NewLine = FALSE;\r
-        Repaint = FALSE;\r
-      } else {\r
-        NewPos  = Link;\r
+        MoveToNextStatement (FALSE, &Link, BottomRow - TopRow);\r
       }\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
@@ -2987,21 +2925,49 @@ UiDisplayMenu (
       // the Date/Time op-code.\r
       //\r
       SavedListEntry = NewPos;\r
-      DistanceValue  = AdjustDateAndTimePosition (FALSE, &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
-        DistanceValue  += MoveToNextStatement (FALSE, &NewPos);\r
+        Difference      = 0;\r
+        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\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
+            //\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
 \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, &OptionString, (UINTN) SkipValue);\r
-        DistanceValue  += NextMenuOption->Skip;\r
+        DistanceValue  = Difference + NextMenuOption->Skip;\r
 \r
         Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
         if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
@@ -3092,30 +3058,39 @@ UiDisplayMenu (
 \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
+          //\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
         }\r
 \r
         MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
 \r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
 \r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiUp;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\r
         //\r
-        // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+        // Scroll to the first page.\r
         //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\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
+        NewLine       = TRUE;\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
       }\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
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
       break;\r
 \r
     case CfUiSave:\r
@@ -3124,12 +3099,12 @@ UiDisplayMenu (
       //\r
       // Submit the form\r
       //\r
-      Status = SubmitForm (Selection->FormSet, Selection->Form);\r
+      Status = SubmitForm (Selection->FormSet, Selection->Form, FALSE);\r
 \r
       if (!EFI_ERROR (Status)) {\r
         ASSERT(MenuOption != NULL);\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
-        UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
       } else {\r
         do {\r
           CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
@@ -3158,7 +3133,8 @@ UiDisplayMenu (
         //\r
         // Show NV update flag on status bar\r
         //\r
-        gNvUpdateRequired = TRUE;\r
+        UpdateNvInfoInForm(Selection->FormSet, TRUE);\r
+        gResetRequired = TRUE;\r
       }\r
       break;\r
 \r