+/**\r
+ Get the index info for this opcode.\r
+\r
+ @param OpCode The input opcode for the statement.\r
+\r
+ @retval The index of this statement.\r
+\r
+**/\r
+UINTN\r
+GetIndexInfoForOpcode (\r
+ IN EFI_IFR_OP_HEADER *OpCode\r
+ )\r
+{\r
+ LIST_ENTRY *NewPos;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN Index;\r
+\r
+ NewPos = gMenuOption.ForwardLink;\r
+ Index = 0;\r
+\r
+ for (NewPos = gMenuOption.ForwardLink; NewPos != &gMenuOption; NewPos = NewPos->ForwardLink){\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+ if (CompareMem (MenuOption->ThisTag->OpCode, OpCode, OpCode->Length) == 0) {\r
+ if (MenuOption->ThisTag->OpCode == OpCode) {\r
+ return Index;\r
+ }\r
+\r
+ Index ++;\r
+ }\r
+ }\r
+\r
+ return Index;\r
+}\r
+\r
+/**\r
+ Is this the saved highlight statement.\r
+\r
+ @param HighLightedStatement The input highlight statement.\r
+\r
+ @retval TRUE This is the highlight statement.\r
+ @retval FALSE This is not the highlight statement.\r
+\r
+**/\r
+BOOLEAN\r
+IsSavedHighlightStatement (\r
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement\r
+ )\r
+{\r
+ if ((gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) &&\r
+ (gFormData->FormId == gHighligthMenuInfo.FormId)) {\r
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {\r
+ return (BOOLEAN) (gHighligthMenuInfo.HLTQuestionId == GetQuestionIdInfo (HighLightedStatement->OpCode));\r
+ } else {\r
+ if (CompareMem (gHighligthMenuInfo.HLTOpCode, HighLightedStatement->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {\r
+ if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(HighLightedStatement->OpCode)) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Is this the highlight menu.\r
+\r
+ @param MenuOption The input Menu option.\r
+\r
+ @retval TRUE This is the highlight menu option.\r
+ @retval FALSE This is not the highlight menu option.\r
+\r
+**/\r
+BOOLEAN\r
+IsHighLightMenuOption (\r
+ IN UI_MENU_OPTION *MenuOption\r
+ )\r
+{\r
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {\r
+ if (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.HLTQuestionId) {\r
+ return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);\r
+ }\r
+ } else {\r
+ if(CompareMem (gHighligthMenuInfo.HLTOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {\r
+ if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {\r
+ return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);\r
+ } else {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find the highlight menu.\r
+\r
+ If the input is NULL, base on the record highlight info in\r
+ gHighligthMenuInfo to find the last highlight menu.\r
+\r
+ @param HighLightedStatement The input highlight statement.\r
+\r
+ @retval The highlight menu index.\r
+\r
+**/\r
+LIST_ENTRY *\r
+FindHighLightMenuOption (\r
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement\r
+ )\r
+{\r
+ LIST_ENTRY *NewPos;\r
+ UI_MENU_OPTION *MenuOption;\r
+\r
+ NewPos = gMenuOption.ForwardLink;\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+ if (HighLightedStatement != NULL) {\r
+ while (MenuOption->ThisTag != HighLightedStatement) {\r
+ NewPos = NewPos->ForwardLink;\r
+ if (NewPos == &gMenuOption) {\r
+ //\r
+ // Not Found it, break\r
+ //\r
+ break;\r
+ }\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ }\r
+\r
+ //\r
+ // Must find the highlight statement.\r
+ //\r
+ ASSERT (NewPos != &gMenuOption);\r
+\r
+ } else {\r
+ while (!IsHighLightMenuOption (MenuOption)) {\r
+ NewPos = NewPos->ForwardLink;\r
+ if (NewPos == &gMenuOption) {\r
+ //\r
+ // Not Found it, break\r
+ //\r
+ break;\r
+ }\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ }\r
+\r
+ //\r
+ // Highlight statement has disappear (suppressed/disableed)\r
+ //\r
+ if (NewPos == &gMenuOption) {\r
+ NewPos = NULL;\r
+ }\r
+ }\r
+\r
+ return NewPos;\r
+}\r
+\r
+/**\r
+ Is this the Top of screen menu.\r
+\r
+ @param MenuOption The input Menu option.\r
+\r
+ @retval TRUE This is the Top of screen menu option.\r
+ @retval FALSE This is not the Top of screen menu option.\r
+\r
+**/\r
+BOOLEAN\r
+IsTopOfScreeMenuOption (\r
+ IN UI_MENU_OPTION *MenuOption\r
+ )\r
+{\r
+ if (gHighligthMenuInfo.TOSQuestionId != 0) {\r
+ return (BOOLEAN) (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.TOSQuestionId);\r
+ }\r
+\r
+ if(CompareMem (gHighligthMenuInfo.TOSOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.TOSOpCode->Length) == 0) {\r
+ if (gHighligthMenuInfo.TOSIndex == 0 || gHighligthMenuInfo.TOSIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Calculate the distance between two menus and include the skip value of StartMenu.\r
+\r
+ @param StartMenu The link_entry pointer to start menu.\r
+ @param EndMenu The link_entry pointer to end menu.\r
+\r
+**/\r
+UINTN\r
+GetDistanceBetweenMenus(\r
+ IN LIST_ENTRY *StartMenu,\r
+ IN LIST_ENTRY *EndMenu\r
+)\r
+{\r
+ LIST_ENTRY *Link;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN Distance;\r
+\r
+ Distance = 0;\r
+\r
+ Link = StartMenu;\r
+ while (Link != EndMenu) {\r
+ MenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ if (MenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (MenuOption);\r
+ }\r
+ Distance += MenuOption->Skip;\r
+ Link = Link->BackLink;\r
+ }\r
+ return Distance;\r
+}\r
+\r
+/**\r
+ Find the top of screen menu base on the previous record menu info.\r
+\r
+ @param HighLightMenu The link_entry pointer to highlight menu.\r
+\r
+ @retval Return the the link_entry pointer top of screen menu.\r
+\r
+**/\r
+LIST_ENTRY *\r
+FindTopOfScreenMenuOption (\r
+ IN LIST_ENTRY *HighLightMenu\r
+ )\r
+{\r
+ LIST_ENTRY *NewPos;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN TopRow;\r
+ UINTN BottomRow;\r
+\r
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;\r
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
+\r
+ NewPos = gMenuOption.ForwardLink;\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+ while (!IsTopOfScreeMenuOption(MenuOption)) {\r
+ NewPos = NewPos->ForwardLink;\r
+ if (NewPos == &gMenuOption) {\r
+ //\r
+ // Not Found it, break\r
+ //\r
+ break;\r
+ }\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ }\r
+\r
+ //\r
+ // Last time top of screen menu has disappeared.\r
+ //\r
+ if (NewPos == &gMenuOption) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Check whether highlight menu and top of screen menu can be shown within one page,\r
+ // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus\r
+ // may be dynamically inserted between highlightmenu and previous top of screen menu,\r
+ // So previous record top of screen menu is not appropriate for current display.\r
+ //\r
+ if (GetDistanceBetweenMenus (HighLightMenu, NewPos) + 1 > BottomRow - TopRow) {\r
+ return NULL;\r
+ }\r
+\r
+ return NewPos;\r
+}\r
+\r