]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
Refine the logic, keep highlight on the selectable menu, and base on priority order...
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
index 1b754cf82bd8f54af4931ee7bd092347c4ec3622..e2c6b292255aebadad5918feda84fe7d57863839 100644 (file)
@@ -852,6 +852,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
@@ -869,7 +917,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
@@ -884,19 +932,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
@@ -906,6 +959,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
@@ -917,28 +975,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
@@ -947,21 +1001,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
@@ -1355,6 +1396,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
@@ -1369,16 +1462,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
@@ -1390,7 +1481,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
@@ -1431,53 +1522,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
-  }\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
+    BottomRow = gHighligthMenuInfo.DisplayRow + 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
@@ -1907,7 +1962,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
@@ -1916,7 +1971,6 @@ UiDisplayMenu (
   UINTN                           Temp2;\r
   UINTN                           TopRow;\r
   UINTN                           BottomRow;\r
-  UINTN                           OriginalRow;\r
   UINTN                           Index;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
@@ -1951,7 +2005,6 @@ UiDisplayMenu (
   UINTN                           HelpHeaderLine;\r
   UINTN                           HelpBottomLine;\r
   BOOLEAN                         MultiHelpPage;\r
-  UINT16                          GlyphWidth;\r
   UINT16                          EachLineWidth;\r
   UINT16                          HeaderLineWidth;\r
   UINT16                          BottomLineWidth;\r
@@ -2212,79 +2265,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 - 1;\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, 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
@@ -2299,79 +2288,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 - 1;\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 (MenuOption, 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
@@ -2381,6 +2304,10 @@ 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
         if (IsListEmpty (&gMenuOption)) {\r
           //\r
@@ -2844,6 +2771,7 @@ UiDisplayMenu (
 \r
     case CfUiUp:\r
       ControlFlag = CfRepaint;\r
+      NewLine     = TRUE;\r
 \r
       SavedListEntry = NewPos;\r
 \r
@@ -2852,191 +2780,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
-        if (NewPos->ForwardLink == &gMenuOption) {\r
-          NewLine   = FALSE;\r
-          Repaint   = FALSE;\r
-          break;\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
-        // 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
-        SkipValue       = 0;\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
-        if (TopOfScreen == &gMenuOption) {\r
-          TopOfScreen = gMenuOption.ForwardLink;\r
-          NewPos      = gMenuOption.BackLink;\r
-          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
-          if (Index < PreviousMenuOption->Skip) {\r
-            Repaint = TRUE;\r
-            SkipValue = PreviousMenuOption->Skip - (Index - TopRow);\r
-          } else {\r
-            Repaint = FALSE;\r
-            SkipValue = 0;\r
-          }\r
-        } else if (TopOfScreen != Link) {\r
-          TopOfScreen = Link;\r
-          NewPos      = Link;\r
-          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-          SkipValue = 0;\r
-        } else {\r
-          //\r
-          // Finally we know that NewPos is the last MenuOption can be focused.\r
-          //\r
-          if (SkipValue == 0) {\r
-            Repaint = FALSE;\r
-          }\r
-          NewPos  = Link;\r
-          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
-          SkipValue = 0;\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
+      if (SkipValue >= (INTN) (BottomRow - TopRow + 1)) {\r
         //\r
-        // Move to the option in Next page.\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 (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
-        // 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
@@ -3050,24 +2886,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
-        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (SkipValue + BottomRow - TopRow + 1 < MenuOption->Skip) {\r
-          SkipValue += BottomRow - TopRow + 1;\r
-          NewLine = TRUE;\r
-          Repaint = TRUE;\r
-          break;\r
-        }\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
@@ -3082,10 +2904,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
@@ -3098,13 +2920,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
@@ -3112,6 +2933,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
@@ -3126,7 +2949,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
@@ -3135,182 +2966,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
-        if (NewPos == TopOfScreen) {\r
-          Temp2 = SkipValue;\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
+        // Scroll to the first page.\r
+        //\r
+        if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) { \r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          Repaint     = TRUE;\r
+          MenuOption  = NULL;\r
         } else {\r
-          Temp2 = 0;\r
+          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
         }\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);\r
 \r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        NewLine         = TRUE;\r
-        NewPos          = NewPos->ForwardLink;\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
-        Difference      = 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
+      //\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
-        // Current menu not at the bottom of the form.\r
+        // Get the top screen menu info.\r
         //\r
-        if (BottomRow >= MenuOption->Row + MenuOption->Skip - Temp2) {\r
-          //\r
-          // Find the next selectable menu.\r
-          //\r
-          Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip + Temp2);\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
-          // We hit the end of MenuOption that can be focused\r
-          // so we simply scroll to the first page.\r
+          // Skip the top op-code\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
+          TopOfScreen   = TopOfScreen->ForwardLink;\r
+          DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\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 - Temp2;\r
-\r
-        Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
-        if ((MenuOption->Row + MenuOption->Skip - Temp2 == BottomRow + 1) &&\r
-            (NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP ||\r
-             NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)\r
-            ) {\r
-          Temp ++;\r
-        }\r
+          SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
 \r
-        //\r
-        // If we are going to scroll, update TopOfScreen\r
-        //\r
-        if (Temp > BottomRow) {\r
-          do {\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
-            // 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
+            // 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
-            // 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
-          Repaint       = TRUE;\r
-        } else if (!IsSelectable (NextMenuOption)) {\r
+          }\r
           //\r
-          // Continue to go down until scroll to next page or the selectable option is found.\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
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
-        }\r
-\r
-        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
-\r
-        UpdateStatusBar (INPUT_ERROR, FALSE);\r
-\r
-      } else {\r
-        //\r
-        // Scroll to the first page.\r
-        //\r
-        if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) {\r
-          TopOfScreen = gMenuOption.ForwardLink;\r
-          Repaint     = TRUE;\r
-          MenuOption  = NULL;\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