+ 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
+/**\r
+ Find the first menu which will be show at the top.\r
+\r
+ @param FormData The data info for this form.\r
+ @param TopOfScreen The link_entry pointer to top menu.\r
+ @param HighlightMenu The menu which will be highlight.\r
+ @param SkipValue The skip value for the top menu.\r
+\r
+**/\r
+VOID\r
+FindTopMenu (\r
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,\r
+ OUT LIST_ENTRY **TopOfScreen,\r
+ OUT LIST_ENTRY **HighlightMenu,\r
+ OUT UINTN *SkipValue\r
+ )\r
+{\r
+ UINTN TopRow;\r
+ UINTN BottomRow;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN TmpValue;\r
+\r
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;\r
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
+ //\r
+ // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,\r
+ // and the other is exit current form and enter last form, it can be covered by the else case.\r
+ //\r
+ if (gMisMatch && gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle && gFormData->FormId == gHighligthMenuInfo.FormId) {\r
+ //\r
+ // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),\r
+ // base on the record highlight info to find the highlight menu.\r
+ //\r
+\r
+ *HighlightMenu = FindHighLightMenuOption(NULL);\r
+ if (*HighlightMenu != NULL) {\r
+ //\r
+ // Update skip info for this highlight menu.\r
+ //\r
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
+ UpdateOptionSkipLines (MenuOption);\r
+\r
+ //\r
+ // Found the last time highlight menu.\r
+ //\r
+ *TopOfScreen = FindTopOfScreenMenuOption(*HighlightMenu);\r
+ if (*TopOfScreen != NULL) {\r
+ //\r
+ // Found the last time selectable top of screen menu.\r
+ //\r
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);\r
+ UpdateOptionSkipLines (MenuOption);\r
+\r
+ *SkipValue = gHighligthMenuInfo.SkipValue;\r
+ } else {\r
+ //\r
+ // Not found last time top of screen menu, so base on current highlight menu\r
+ // to find the new top of screen menu.\r
+ // Make the current highlight menu at the bottom of the form to calculate the\r
+ // top of screen menu.\r
+ //\r
+ if (MenuOption->Skip >= BottomRow - TopRow) {\r
+ *TopOfScreen = *HighlightMenu;\r
+ TmpValue = 0;\r
+ } else {\r
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
+ }\r
+\r
+ *SkipValue = TmpValue;\r
+ }\r
+ } else {\r
+ //\r
+ // Last time highlight menu has disappear, find the first highlightable menu as the default one.\r
+ //\r
+ *HighlightMenu = gMenuOption.ForwardLink;\r
+ if (!IsListEmpty (&gMenuOption)) {\r
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);\r
+ }\r
+ *TopOfScreen = gMenuOption.ForwardLink;\r
+ *SkipValue = 0;\r
+ }\r
+\r
+ } else if (FormData->HighLightedStatement != NULL) {\r
+ if (IsSavedHighlightStatement (FormData->HighLightedStatement)) {\r
+ //\r
+ // Input highlight menu is same as last time highlight menu.\r
+ // Base on last time highlight menu to set the top of screen menu and highlight menu.\r
+ //\r
+ *HighlightMenu = FindHighLightMenuOption(NULL);\r
+ ASSERT (*HighlightMenu != NULL);\r
+\r
+ //\r
+ // Update skip info for this highlight menu.\r
+ //\r
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
+ UpdateOptionSkipLines (MenuOption);\r
+\r
+ *TopOfScreen = FindTopOfScreenMenuOption(*HighlightMenu);\r
+ if (*TopOfScreen == NULL) {\r
+ //\r
+ // Not found last time top of screen menu, so base on current highlight menu\r
+ // to find the new top of screen menu.\r
+ // Make the current highlight menu at the bottom of the form to calculate the\r
+ // top of screen menu.\r
+ //\r
+ if (MenuOption->Skip >= BottomRow - TopRow) {\r
+ *TopOfScreen = *HighlightMenu;\r
+ TmpValue = 0;\r
+ } else {\r
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
+ }\r
+\r
+ *SkipValue = TmpValue;\r
+ } else {\r
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);\r
+ UpdateOptionSkipLines (MenuOption);\r
+\r
+ *SkipValue = gHighligthMenuInfo.SkipValue;\r
+ }\r
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
+ } else {\r
+ //\r
+ // Input highlight menu is not save as last time highlight menu.\r
+ //\r
+ *HighlightMenu = FindHighLightMenuOption(FormData->HighLightedStatement);\r
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);\r
+ UpdateOptionSkipLines (MenuOption);\r
+\r
+ //\r
+ // Make the current highlight menu at the bottom of the form to calculate the\r
+ // top of screen menu.\r
+ //\r
+ if (MenuOption->Skip >= BottomRow - TopRow) {\r
+ *TopOfScreen = *HighlightMenu;\r
+ TmpValue = 0;\r
+ } else {\r
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);\r
+ }\r
+\r
+ *SkipValue = TmpValue;\r
+ }\r
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);\r
+ } else {\r
+ //\r
+ // If not has input highlight statement, just return the first one in this form.\r
+ //\r
+ *TopOfScreen = gMenuOption.ForwardLink;\r
+ *HighlightMenu = gMenuOption.ForwardLink;\r
+ if (!IsListEmpty (&gMenuOption)) {\r
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);\r
+ }\r
+ *SkipValue = 0;\r
+ }\r
+\r
+ gMisMatch = FALSE;\r
+\r
+ //\r
+ // First enter to show the menu, update highlight info.\r
+ //\r
+ UpdateHighlightMenuInfo (*HighlightMenu, *TopOfScreen, *SkipValue);\r
+}\r
+\r
+/**\r
+ Record the highlight menu and top of screen menu info.\r
+\r
+ @param Highlight The menu opton which is highlight.\r
+ @param TopOfScreen The menu opton which is at the top of the form.\r
+ @param SkipValue The skip line info for the top of screen menu.\r
+\r
+**/\r
+VOID\r
+UpdateHighlightMenuInfo (\r
+ IN LIST_ENTRY *Highlight,\r
+ IN LIST_ENTRY *TopOfScreen,\r
+ IN UINTN SkipValue\r
+ )\r
+{\r
+ UI_MENU_OPTION *MenuOption;\r
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+\r
+ gHighligthMenuInfo.HiiHandle = gFormData->HiiHandle;\r
+ gHighligthMenuInfo.FormId = gFormData->FormId;\r
+ gHighligthMenuInfo.SkipValue = (UINT16)SkipValue;\r
+\r
+ if (!IsListEmpty (&gMenuOption)) {\r
+ MenuOption = MENU_OPTION_FROM_LINK (Highlight);\r
+ Statement = MenuOption->ThisTag;\r
+\r
+ gUserInput->SelectedStatement = Statement;\r
+\r
+ gHighligthMenuInfo.HLTSequence = MenuOption->Sequence;\r
+ gHighligthMenuInfo.HLTQuestionId = GetQuestionIdInfo(Statement->OpCode);\r
+ if (gHighligthMenuInfo.HLTQuestionId == 0) {\r
+ //\r
+ // if question id == 0, save the opcode buffer..\r
+ //\r
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {\r
+ FreePool (gHighligthMenuInfo.HLTOpCode);\r
+ }\r
+ gHighligthMenuInfo.HLTOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);\r
+ ASSERT (gHighligthMenuInfo.HLTOpCode != NULL);\r
+\r
+ gHighligthMenuInfo.HLTIndex = GetIndexInfoForOpcode(Statement->OpCode);\r
+ }\r
+\r
+ MenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+ Statement = MenuOption->ThisTag;\r
+\r
+ gHighligthMenuInfo.TOSQuestionId = GetQuestionIdInfo(Statement->OpCode);\r
+ if (gHighligthMenuInfo.TOSQuestionId == 0) {\r
+ //\r
+ // if question id == 0, save the opcode buffer..\r
+ //\r
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {\r
+ FreePool (gHighligthMenuInfo.TOSOpCode);\r
+ }\r
+ gHighligthMenuInfo.TOSOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);\r
+ ASSERT (gHighligthMenuInfo.TOSOpCode != NULL);\r
+\r
+ gHighligthMenuInfo.TOSIndex = GetIndexInfoForOpcode(Statement->OpCode);\r
+ }\r
+ } else {\r
+ gUserInput->SelectedStatement = NULL;\r
+\r
+ gHighligthMenuInfo.HLTSequence = 0;\r
+ gHighligthMenuInfo.HLTQuestionId = 0;\r
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {\r
+ FreePool (gHighligthMenuInfo.HLTOpCode);\r
+ }\r
+ gHighligthMenuInfo.HLTOpCode = NULL;\r
+ gHighligthMenuInfo.HLTIndex = 0;\r
+\r
+ gHighligthMenuInfo.TOSQuestionId = 0;\r
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {\r
+ FreePool (gHighligthMenuInfo.TOSOpCode);\r
+ }\r
+ gHighligthMenuInfo.TOSOpCode = NULL;\r
+ gHighligthMenuInfo.TOSIndex = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Update attribut for this menu.\r
+\r
+ @param MenuOption The menu opton which this attribut used to.\r
+ @param Highlight Whether this menu will be highlight.\r
+\r
+**/\r
+VOID\r
+SetDisplayAttribute (\r
+ IN UI_MENU_OPTION *MenuOption,\r
+ IN BOOLEAN Highlight\r
+ )\r
+{\r
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+\r
+ Statement = MenuOption->ThisTag;\r
+\r
+ if (Highlight) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
+ return;\r
+ }\r
+\r
+ if (MenuOption->GrayOut) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
+ } else {\r
+ if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
+ } else {\r
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Print string for this menu option.\r
+\r
+ @param MenuOption The menu opton which this attribut used to.\r
+ @param Col The column that this string will be print at.\r
+ @param Row The row that this string will be print at.\r
+ @param String The string which need to print.\r
+ @param Width The width need to print, if string is less than the\r
+ width, the block space will be used.\r
+ @param Highlight Whether this menu will be highlight.\r
+\r
+**/\r
+VOID\r
+DisplayMenuString (\r
+ IN UI_MENU_OPTION *MenuOption,\r
+ IN UINTN Col,\r
+ IN UINTN Row,\r
+ IN CHAR16 *String,\r
+ IN UINTN Width,\r
+ IN BOOLEAN Highlight\r
+ )\r
+{\r
+ UINTN Length;\r
+\r
+ //\r
+ // Print string with normal color.\r
+ //\r
+ if (!Highlight) {\r
+ PrintStringAtWithWidth (Col, Row, String, Width);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Print the highlight menu string.\r
+ // First print the highlight string.\r
+ //\r
+ SetDisplayAttribute(MenuOption, TRUE);\r
+ Length = PrintStringAt (Col, Row, String);\r
+\r
+ //\r
+ // Second, clean the empty after the string.\r
+ //\r
+ SetDisplayAttribute(MenuOption, FALSE);\r
+ PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);\r
+}\r
+\r
+/**\r
+ Check whether this menu can has option string.\r
+\r
+ @param MenuOption The menu opton which this attribut used to.\r