of the given parent menu.\r
\r
@param Parent The parent of menu to be added.\r
+ @param HiiHandle Hii handle related to this formset.\r
@param FormSetGuid The Formset Guid of menu to be added.\r
@param FormId The Form ID of menu to be added.\r
\r
UI_MENU_LIST *\r
UiAddMenuList (\r
IN OUT UI_MENU_LIST *Parent,\r
+ IN EFI_HII_HANDLE HiiHandle,\r
IN EFI_GUID *FormSetGuid,\r
IN UINT16 FormId\r
)\r
MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
InitializeListHead (&MenuList->ChildListHead);\r
\r
+ MenuList->HiiHandle = HiiHandle;\r
CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
MenuList->FormId = FormId;\r
MenuList->Parent = Parent;\r
\r
\r
/**\r
- Search Menu with given FormId in the parent menu and all its child menus.\r
+ Search Menu with given FormId and FormSetGuid in all cached menu list.\r
\r
@param Parent The parent of menu to search.\r
+ @param FormSetGuid The Formset GUID of the menu to search. \r
@param FormId The Form ID of menu to search.\r
\r
@return A pointer to menu found or NULL if not found.\r
UI_MENU_LIST *\r
UiFindChildMenuList (\r
IN UI_MENU_LIST *Parent,\r
+ IN EFI_GUID *FormSetGuid, \r
IN UINT16 FormId\r
)\r
{\r
UI_MENU_LIST *Child;\r
UI_MENU_LIST *MenuList;\r
\r
- if (Parent->FormId == FormId) {\r
+ ASSERT (Parent != NULL);\r
+\r
+ if (Parent->FormId == FormId && CompareGuid (FormSetGuid, &Parent->FormSetGuid)) {\r
return Parent;\r
}\r
\r
while (!IsNull (&Parent->ChildListHead, Link)) {\r
Child = UI_MENU_LIST_FROM_LINK (Link);\r
\r
- MenuList = UiFindChildMenuList (Child, FormId);\r
+ MenuList = UiFindChildMenuList (Child, FormSetGuid, FormId);\r
if (MenuList != NULL) {\r
return MenuList;\r
}\r
while (!IsNull (&gMenuList, Link)) {\r
MenuList = UI_MENU_LIST_FROM_LINK (Link);\r
\r
- if (CompareGuid (FormSetGuid, &MenuList->FormSetGuid)) {\r
- //\r
- // This is the formset we are looking for, find the form in this formset\r
- //\r
- Child = UiFindChildMenuList (MenuList, FormId);\r
- if (Child != NULL) {\r
- return Child;\r
- }\r
+ Child = UiFindChildMenuList(MenuList, FormSetGuid, FormId);\r
+ if (Child != NULL) {\r
+ return Child;\r
}\r
\r
Link = GetNextNode (&gMenuList, Link);\r
\r
@param Selection The user's selection.\r
@param MenuOption The MenuOption to be checked.\r
- @param OptionalString The option string.\r
- @param SkipValue The number of lins to skip.\r
\r
**/\r
VOID\r
UpdateOptionSkipLines (\r
IN UI_MENU_SELECTION *Selection,\r
- IN UI_MENU_OPTION *MenuOption,\r
- OUT CHAR16 **OptionalString,\r
- IN UINTN SkipValue\r
+ IN UI_MENU_OPTION *MenuOption\r
)\r
{\r
UINTN Index;\r
CHAR16 *OptionString;\r
\r
Row = 0;\r
- OptionString = *OptionalString;\r
- OutputString = NULL;\r
-\r
+ OptionString = NULL;\r
ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
\r
if (OptionString != NULL) {\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 (SkipValue == 0) {\r
- Row++;\r
- //\r
- // Since the Number of lines for this menu entry may or may not be reflected accurately\r
- // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
- // some testing to ensure we are keeping this in-sync.\r
- //\r
- // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
- //\r
- if ((Row - OriginalRow) >= MenuOption->Skip) {\r
- MenuOption->Skip++;\r
- }\r
+ Row++;\r
+ //\r
+ // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+ // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+ // some testing to ensure we are keeping this in-sync.\r
+ //\r
+ // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+ //\r
+ if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+ MenuOption->Skip++;\r
}\r
}\r
\r
FreePool (OutputString);\r
- if (SkipValue != 0) {\r
- SkipValue--;\r
- }\r
}\r
\r
Row = OriginalRow;\r
}\r
\r
- *OptionalString = OptionString;\r
+ if (OptionString != NULL) {\r
+ FreePool (OptionString);\r
+ }\r
}\r
\r
\r
\r
This is an internal function.\r
\r
+ @param Selection Menu selection.\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
INTN\r
MoveToNextStatement (\r
+ IN UI_MENU_SELECTION *Selection,\r
IN BOOLEAN GoUp,\r
IN OUT LIST_ENTRY **CurrentPosition,\r
IN UINTN GapToTop\r
\r
while (TRUE) {\r
NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+ if (NextMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, NextMenuOption);\r
+ }\r
+ \r
if (GoUp && (PreMenuOption != NextMenuOption)) {\r
//\r
// Current Position doesn't need to be caculated when go up.\r
return HiiHandle;\r
}\r
\r
+/**\r
+ Find HII Handle in the HII database associated with given form set guid.\r
+\r
+ If FormSetGuid is NULL, then ASSERT.\r
+\r
+ @param ComparingGuid FormSet Guid associated with the HII package list\r
+ handle.\r
+\r
+ @retval Handle HII package list Handle associated with the Device\r
+ Path.\r
+ @retval NULL Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+ EFI_GUID *ComparingGuid\r
+ )\r
+{\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ UINTN Index;\r
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
+ UINTN BufferSize;\r
+ UINT32 Offset;\r
+ UINT32 Offset2;\r
+ UINT32 PackageListLength;\r
+ EFI_HII_PACKAGE_HEADER PackageHeader;\r
+ UINT8 *Package;\r
+ UINT8 *OpCodeData;\r
+ EFI_STATUS Status;\r
+ EFI_HII_HANDLE HiiHandle;\r
+\r
+ ASSERT (ComparingGuid != NULL);\r
+\r
+ HiiHandle = NULL;\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ HiiHandles = HiiGetHiiHandles (NULL);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ //\r
+ // Search for formset of each class type\r
+ //\r
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+ BufferSize = 0;\r
+ HiiPackageList = NULL;\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ HiiPackageList = AllocatePool (BufferSize);\r
+ ASSERT (HiiPackageList != NULL);\r
+\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+ }\r
+ if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Get Form package from this HII package List\r
+ //\r
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+ Offset2 = 0;\r
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+ while (Offset < PackageListLength) {\r
+ Package = ((UINT8 *) HiiPackageList) + Offset;\r
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+ //\r
+ // Search FormSet in this Form Package\r
+ //\r
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+ while (Offset2 < PackageHeader.Length) {\r
+ OpCodeData = Package + Offset2;\r
+\r
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+ //\r
+ // Try to compare against formset GUID\r
+ //\r
+ if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+ }\r
+ }\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ Offset += PackageHeader.Length;\r
+ }\r
+ \r
+ FreePool (HiiPackageList);\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HiiHandles);\r
+\r
+ return HiiHandle;\r
+}\r
+\r
/**\r
Process the goto op code, update the info in the selection structure.\r
\r
EFI_INPUT_KEY Key;\r
EFI_STATUS Status;\r
UI_MENU_LIST *MenuList;\r
+ BOOLEAN UpdateFormInfo;\r
\r
Status = EFI_SUCCESS;\r
+ UpdateFormInfo = TRUE;\r
\r
if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
if (Selection->Form->ModalForm) {\r
// Goto another Formset, check for uncommitted data\r
//\r
Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ \r
+ Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+ if (Selection->Handle == NULL) {\r
+ //\r
+ // If target Hii Handle not found, exit\r
+ //\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ Selection->Statement = NULL;\r
+ return Status;\r
+ } \r
\r
CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
//\r
Selection->Action = UI_ACTION_REFRESH_FORM;\r
\r
- //\r
- // Link current form so that we can always go back when someone hits the ESC\r
- //\r
- MenuList = UiFindMenuList (&Selection->FormSetGuid, Statement->HiiValue.Value.ref.FormId);\r
- if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
- MenuList = UiAddMenuList (Selection->CurrentMenu, &Selection->FormSetGuid, Statement->HiiValue.Value.ref.FormId);\r
- }\r
-\r
Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
} else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
*NewLine = TRUE;\r
}\r
}\r
+ UpdateFormInfo = FALSE;\r
} else {\r
if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
Selection->Action = UI_ACTION_REFRESH_FORM;\r
}\r
+ UpdateFormInfo = FALSE;\r
+ }\r
+\r
+ if (UpdateFormInfo) {\r
+ //\r
+ // Link current form so that we can always go back when someone hits the ESC\r
+ //\r
+ MenuList = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
+ if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
+ MenuList = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
+ }\r
}\r
\r
return Status;\r
//\r
// Current menu not found, add it to the menu tree\r
//\r
- CurrentMenu = UiAddMenuList (NULL, &Selection->FormSetGuid, Selection->FormId);\r
+ CurrentMenu = UiAddMenuList (NULL, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
}\r
ASSERT (CurrentMenu != NULL);\r
Selection->CurrentMenu = CurrentMenu;\r
ControlFlag = CfUpdateHelpString;\r
if (InitializedFlag) {\r
InitializedFlag = FALSE;\r
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
}\r
\r
//\r
for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
Index += SavedMenuOption->Skip;\r
+ if (Link == TopOfScreen) {\r
+ Index -= OldSkipValue;\r
+ }\r
Link = Link->ForwardLink;\r
}\r
+ if (NewPos == Link) {\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ }\r
\r
- if (Link != NewPos || Index > BottomRow) {\r
+ if (Link != NewPos || Index > BottomRow || (Link == NewPos && SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow)) {\r
+ //\r
+ // Find the MenuOption which has the skip value for Date/Time opcode. \r
+ //\r
+ AdjustDateAndTimePosition(FALSE, &NewPos);\r
//\r
// NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
//\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ //\r
+ // SavedMenuOption->Row == 0 means the menu not show yet.\r
+ //\r
+ if (SavedMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+ }\r
+ \r
Link = NewPos;\r
- for (Index = TopRow; Index <= BottomRow; ) {\r
+ for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) { \r
Link = Link->BackLink;\r
SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ if (SavedMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+ }\r
Index += SavedMenuOption->Skip;\r
}\r
- TopOfScreen = Link->ForwardLink;\r
+ \r
+ SkipValue = Index - BottomRow - 1;\r
+ if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+ TopOfScreen = Link;\r
+ OldSkipValue = SkipValue;\r
+ } else {\r
+ SkipValue = 0;\r
+ TopOfScreen = Link->ForwardLink;\r
+ }\r
\r
Repaint = TRUE;\r
NewLine = TRUE;\r
NewPos = NewPos->BackLink;\r
\r
PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ if (PreviousMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, 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
+ Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
}\r
NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
\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 (Selection, PreviousMenuOption);\r
+ } \r
if (Index < PreviousMenuOption->Skip) {\r
Index = 0;\r
break;\r
if (TopOfScreen == &gMenuOption) {\r
TopOfScreen = gMenuOption.ForwardLink;\r
NewPos = gMenuOption.BackLink;\r
- MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, 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
+ MoveToNextStatement (Selection, 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
+ MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
}\r
} else {\r
if (Index + 1 < TopRow) {\r
//\r
if (TopOfScreen == &gMenuOption) {\r
NewPos = gMenuOption.BackLink;\r
- MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
} else {\r
NewPos = Link;\r
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
}\r
\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
+ MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
} else {\r
if (Index - 1 > BottomRow) {\r
//\r
//\r
// Move to the option in Next page.\r
//\r
- MoveToNextStatement (FALSE, &Link, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
}\r
\r
//\r
\r
Difference = 0;\r
if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
- Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
+ Difference = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
//\r
// We hit the end of MenuOption that can be focused\r
// so we simply scroll to the first page.\r
MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
}\r
NewPos = gMenuOption.ForwardLink;\r
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, 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
// 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
+ UpdateOptionSkipLines (Selection, NextMenuOption);\r
DistanceValue = Difference + NextMenuOption->Skip;\r
\r
Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
}\r
NewLine = TRUE;\r
NewPos = gMenuOption.ForwardLink;\r
- MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+ MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
}\r
\r
//\r