/** @file\r
Utility functions for User Interface functions.\r
\r
-Copyright (c) 2004 - 2009, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
\r
LIST_ENTRY gMenuOption;\r
LIST_ENTRY gMenuList = INITIALIZE_LIST_HEAD_VARIABLE (gMenuList);\r
-MENU_REFRESH_ENTRY *gMenuRefreshHead;\r
+MENU_REFRESH_ENTRY *gMenuRefreshHead; // Menu list used for refresh timer opcode.\r
+MENU_REFRESH_ENTRY *gMenuEventGuidRefreshHead; // Menu list used for refresh event guid opcode.\r
\r
//\r
// Search table for UiDisplayMenu()\r
{\r
SCAN_RIGHT,\r
UiRight,\r
- },\r
- {\r
- SCAN_F9,\r
- UiDefault,\r
- },\r
- {\r
- SCAN_F10,\r
- UiSave\r
}\r
};\r
\r
+UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);\r
+\r
SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
{\r
UiNoOperation,\r
CfUiNoOperation,\r
},\r
- {\r
- UiDefault,\r
- CfUiDefault,\r
- },\r
{\r
UiSelect,\r
CfUiSelect,\r
UiReset,\r
CfUiReset,\r
},\r
- {\r
- UiSave,\r
- CfUiSave,\r
- },\r
{\r
UiPageUp,\r
CfUiPageUp,\r
{\r
UiPageDown,\r
CfUiPageDown\r
+ }, \r
+ {\r
+ UiHotKey,\r
+ CfUiHotKey\r
}\r
};\r
\r
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
gMenuRefreshHead = OldMenuRefreshEntry;\r
}\r
\r
- gMenuRefreshHead = NULL;\r
+ while (gMenuEventGuidRefreshHead != NULL) {\r
+ OldMenuRefreshEntry = gMenuEventGuidRefreshHead->Next;\r
+ if (gMenuEventGuidRefreshHead != NULL) {\r
+ gBS->CloseEvent(gMenuEventGuidRefreshHead->Event);\r
+ }\r
+ FreePool (gMenuEventGuidRefreshHead);\r
+ gMenuEventGuidRefreshHead = OldMenuRefreshEntry;\r
+ }\r
}\r
\r
\r
+/**\r
+ Process option string for date/time opcode.\r
+\r
+ @param MenuOption Menu option point to date/time.\r
+ @param OptionString Option string input for process.\r
+ @param AddOptCol Whether need to update MenuOption->OptCol. \r
+\r
+**/\r
+VOID \r
+ProcessStringForDateTime (\r
+ UI_MENU_OPTION *MenuOption,\r
+ CHAR16 *OptionString,\r
+ BOOLEAN AddOptCol\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Count;\r
+ FORM_BROWSER_STATEMENT *Statement;\r
+\r
+ ASSERT (MenuOption != NULL && OptionString != NULL);\r
+ \r
+ Statement = MenuOption->ThisTag;\r
+ \r
+ //\r
+ // If leading spaces on OptionString - remove the spaces\r
+ //\r
+ for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+ //\r
+ // Base on the blockspace to get the option column info.\r
+ //\r
+ if (AddOptCol) {\r
+ MenuOption->OptCol++;\r
+ }\r
+ }\r
+ \r
+ for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+ OptionString[Count] = OptionString[Index];\r
+ Count++;\r
+ }\r
+ OptionString[Count] = CHAR_NULL;\r
+ \r
+ //\r
+ // Enable to suppress field in the opcode base on the flag.\r
+ //\r
+ if (Statement->Operand == EFI_IFR_DATE_OP) {\r
+ //\r
+ // OptionString format is: <**: **: ****>\r
+ // |month|day|year|\r
+ // 4 3 5\r
+ //\r
+ if ((Statement->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+ //\r
+ // At this point, only "<**:" in the optionstring. \r
+ // Clean the day's ** field, after clean, the format is "< :"\r
+ //\r
+ SetUnicodeMem (&OptionString[1], 2, L' ');\r
+ } else if ((Statement->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+ //\r
+ // At this point, only "**:" in the optionstring. \r
+ // Clean the month's "**" field, after clean, the format is " :"\r
+ // \r
+ SetUnicodeMem (&OptionString[0], 2, L' ');\r
+ } else if ((Statement->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+ //\r
+ // At this point, only "****>" in the optionstring. \r
+ // Clean the year's "****" field, after clean, the format is " >"\r
+ // \r
+ SetUnicodeMem (&OptionString[0], 4, L' ');\r
+ }\r
+ } else if (Statement->Operand == EFI_IFR_TIME_OP) {\r
+ //\r
+ // OptionString format is: <**: **: **>\r
+ // |hour|minute|second|\r
+ // 4 3 3\r
+ //\r
+ if ((Statement->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+ //\r
+ // At this point, only "<**:" in the optionstring. \r
+ // Clean the hour's ** field, after clean, the format is "< :"\r
+ //\r
+ SetUnicodeMem (&OptionString[1], 2, L' ');\r
+ } else if ((Statement->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+ //\r
+ // At this point, only "**:" in the optionstring. \r
+ // Clean the minute's "**" field, after clean, the format is " :"\r
+ // \r
+ SetUnicodeMem (&OptionString[0], 2, L' ');\r
+ } else if ((Statement->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+ //\r
+ // At this point, only "**>" in the optionstring. \r
+ // Clean the second's "**" field, after clean, the format is " >"\r
+ // \r
+ SetUnicodeMem (&OptionString[0], 2, L' ');\r
+ }\r
+ }\r
+}\r
\r
/**\r
- Refresh screen.\r
+ Refresh question.\r
\r
+ @param MenuRefreshEntry Menu refresh structure which has info about the refresh question.\r
**/\r
-EFI_STATUS\r
-RefreshForm (\r
- VOID\r
+EFI_STATUS \r
+RefreshQuestion (\r
+ IN MENU_REFRESH_ENTRY *MenuRefreshEntry\r
)\r
{\r
CHAR16 *OptionString;\r
- MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
- UINTN Index;\r
EFI_STATUS Status;\r
UI_MENU_SELECTION *Selection;\r
FORM_BROWSER_STATEMENT *Question;\r
- EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
- EFI_HII_VALUE *HiiValue;\r
- EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
\r
- if (gMenuRefreshHead != NULL) {\r
+ Selection = MenuRefreshEntry->Selection;\r
+ Question = MenuRefreshEntry->MenuOption->ThisTag;\r
\r
- MenuRefreshEntry = gMenuRefreshHead;\r
+ Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OptionString = NULL;\r
+ ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
\r
+ if (OptionString != NULL) {\r
//\r
- // Reset FormPackage update flag\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
- mHiiPackageListUpdated = FALSE;\r
-\r
- do {\r
- gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
-\r
- Selection = MenuRefreshEntry->Selection;\r
- Question = MenuRefreshEntry->MenuOption->ThisTag;\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
- Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
+ ProcessStringForDateTime(MenuRefreshEntry->MenuOption, OptionString, FALSE);\r
+ PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
+ FreePool (OptionString);\r
+ }\r
\r
- OptionString = NULL;\r
- ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
+ //\r
+ // Question value may be changed, need invoke its Callback()\r
+ //\r
+ Status = ProcessCallBackFunction (Selection, Question, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
\r
- if (OptionString != NULL) {\r
- //\r
- // If leading spaces on OptionString - remove the spaces\r
- //\r
- for (Index = 0; OptionString[Index] == L' '; Index++)\r
- ;\r
+ return Status;\r
+}\r
\r
- PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
- FreePool (OptionString);\r
- }\r
+/**\r
+ Refresh the question which has refresh guid event attribute.\r
+ \r
+ @param Event The event which has this function related. \r
+ @param Context The input context info related to this event or the status code return to the caller.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshQuestionNotify(\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
+ UI_MENU_SELECTION *Selection;\r
\r
- //\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
+ //\r
+ // Reset FormPackage update flag\r
+ //\r
+ mHiiPackageListUpdated = FALSE;\r
\r
- HiiValue = &Question->HiiValue;\r
- if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
- //\r
- // Create String in HII database for Configuration Driver to retrieve\r
- //\r
- HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, Selection->FormSet->HiiHandle);\r
- }\r
+ MenuRefreshEntry = (MENU_REFRESH_ENTRY *)Context;\r
+ ASSERT (MenuRefreshEntry != NULL);\r
+ Selection = MenuRefreshEntry->Selection;\r
\r
- Status = ConfigAccess->Callback (\r
- ConfigAccess,\r
- EFI_BROWSER_ACTION_CHANGING,\r
- Question->QuestionId,\r
- HiiValue->Type,\r
- &HiiValue->Value,\r
- &ActionRequest\r
- );\r
+ RefreshQuestion (MenuRefreshEntry);\r
+ \r
+ if (mHiiPackageListUpdated) {\r
+ //\r
+ // Package list is updated, force to reparse IFR binary of target Formset\r
+ //\r
+ mHiiPackageListUpdated = FALSE;\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ } \r
+}\r
\r
- if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
- //\r
- // Clean the String in HII Database\r
- //\r
- DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
- }\r
\r
- if (!EFI_ERROR (Status)) {\r
- switch (ActionRequest) {\r
- case EFI_BROWSER_ACTION_REQUEST_RESET:\r
- gResetRequired = TRUE;\r
- break;\r
+/**\r
+ Refresh screen.\r
\r
- case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
- SubmitForm (Selection->FormSet, Selection->Form);\r
- break;\r
+**/\r
+EFI_STATUS\r
+RefreshForm (\r
+ VOID\r
+ )\r
+{\r
+ MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
+ EFI_STATUS Status;\r
+ UI_MENU_SELECTION *Selection;\r
\r
- case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
- Selection->Action = UI_ACTION_EXIT;\r
- gNvUpdateRequired = FALSE;\r
- break;\r
+ if (gMenuRefreshHead != NULL) {\r
+ //\r
+ // call from refresh interval process.\r
+ //\r
+ MenuRefreshEntry = gMenuRefreshHead;\r
+ Selection = MenuRefreshEntry->Selection;\r
+ //\r
+ // Reset FormPackage update flag\r
+ //\r
+ mHiiPackageListUpdated = FALSE;\r
\r
- default:\r
- break;\r
- }\r
- }\r
+ do {\r
+ Status = RefreshQuestion (MenuRefreshEntry);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
MenuRefreshEntry = MenuRefreshEntry->Next;\r
\r
@param String String description for this option.\r
@param Handle Hii handle for the package list.\r
+ @param Form The form this statement belong to.\r
@param Statement Statement of this Menu Option.\r
@param NumberOfLines Display lines for this Menu Option.\r
@param MenuItemCount The index for this Option in the Menu.\r
UiAddMenuOption (\r
IN CHAR16 *String,\r
IN EFI_HII_HANDLE Handle,\r
+ IN FORM_BROWSER_FORM *Form,\r
IN FORM_BROWSER_STATEMENT *Statement,\r
IN UINT16 NumberOfLines,\r
IN UINT16 MenuItemCount\r
}\r
MenuOption->Sequence = Index;\r
\r
- if (Statement->GrayOutExpression != NULL) {\r
- MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
+ if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut ) {\r
+ MenuOption->GrayOut = TRUE;\r
+ } else {\r
+ MenuOption->GrayOut = FALSE;\r
}\r
\r
+ //\r
+ // If the form or the question has the lock attribute, deal same as grayout.\r
+ //\r
+ if (Form->Locked || Statement->Locked) {\r
+ MenuOption->GrayOut = TRUE;\r
+ }\r
+ \r
switch (Statement->Operand) {\r
case EFI_IFR_ORDERED_LIST_OP:\r
case EFI_IFR_ONE_OF_OP:\r
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
+ // break skipped on purpose\r
+ //\r
default:\r
MenuOption->IsQuestion = FALSE;\r
break;\r
if ((Statement->ValueExpression != NULL) ||\r
((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
MenuOption->ReadOnly = TRUE;\r
+ if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {\r
+ MenuOption->GrayOut = TRUE;\r
+ }\r
}\r
\r
InsertTailList (&gMenuOption, &MenuOption->Link);\r
\r
**/\r
EFI_STATUS\r
+EFIAPI\r
CreateDialog (\r
IN UINTN NumberOfLines,\r
IN BOOLEAN HotKey,\r
ASSERT (TempString);\r
ASSERT (BufferedString);\r
\r
- VA_START (Marker, KeyValue);\r
-\r
//\r
// Zero the outgoing buffer\r
//\r
\r
LargestString = 0;\r
\r
+ VA_START (Marker, KeyValue);\r
+\r
//\r
// Determine the largest string in the dialog box\r
// Notice we are starting with 1 since String is the first string\r
TempString[Index - 1] = CHAR_NULL;\r
StrCpy (StringBuffer, TempString);\r
}\r
+ //\r
+ // break skipped on purpose\r
+ //\r
\r
default:\r
//\r
\r
**/\r
VOID\r
+EFIAPI\r
CreateMultiStringPopUp (\r
IN UINTN RequestedWidth,\r
IN UINTN NumberOfLines,\r
/**\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
**/\r
VOID\r
UpdateStatusBar (\r
+ IN UI_MENU_SELECTION *Selection,\r
IN UINTN MessageType,\r
IN UINT8 Flags,\r
IN BOOLEAN State\r
UINTN Index;\r
CHAR16 *NvUpdateMessage;\r
CHAR16 *InputErrorMessage;\r
-\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *LocalFormSet;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ \r
NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
\r
);\r
mInputError = TRUE;\r
} else {\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");\r
}\r
break;\r
\r
case NV_UPDATE_REQUIRED:\r
- if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
- if (State) {\r
+ //\r
+ // Global setting support. Show configuration change on every form.\r
+ //\r
+ if (State) {\r
+ gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
+\r
+ if (Selection != NULL && Selection->Statement != NULL) {\r
+ Question = Selection->Statement;\r
+ if (Question->Storage != NULL || Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+ //\r
+ // Update only for Question value that need to be saved into Storage.\r
+ //\r
+ Selection->Form->NvUpdateRequired = TRUE;\r
+ }\r
+ }\r
+ \r
+ if (Selection == NULL || IsNvUpdateRequired (Selection->FormSet)) {\r
gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
PrintStringAt (\r
gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
gScreenDimensions.BottomRow - 1,\r
NvUpdateMessage\r
);\r
- gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
-\r
- gNvUpdateRequired = TRUE;\r
- } else {\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
- for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
- PrintAt (\r
- (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
- gScreenDimensions.BottomRow - 1,\r
- L" "\r
- );\r
- }\r
-\r
- gNvUpdateRequired = FALSE;\r
+ }\r
+ } else {\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
+ for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
+ PrintAt (\r
+ (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
+ gScreenDimensions.BottomRow - 1,\r
+ L" "\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
+ switch (gBrowserSettingScope) {\r
+ case SystemLevel:\r
+ //\r
+ // Check the maintain list to see whether there is any change.\r
+ //\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ if (IsNvUpdateRequired(LocalFormSet)) {\r
+ UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+ break;\r
+ }\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ }\r
+ break;\r
+ case FormSetLevel:\r
+ case FormLevel:\r
+ UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+ default:\r
+ break;\r
}\r
+\r
break;\r
\r
default:\r
Width -= SUBTITLE_INDENT;\r
}\r
\r
- return Width;\r
+ return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
}\r
\r
/**\r
Will copy LineWidth amount of a string in the OutputString buffer and return the\r
number of CHAR16 characters that were copied into the OutputString buffer.\r
+ The output string format is:\r
+ Glyph Info + String info + '\0'.\r
+\r
+ In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
\r
@param InputString String description for this option.\r
@param LineWidth Width of the desired string to extract in CHAR16\r
characters\r
+ @param GlyphWidth The glyph width of the begin of the char in the string.\r
@param Index Where in InputString to start the copy process\r
@param OutputString Buffer to copy the string into\r
\r
- @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
+ @return Returns the number of CHAR16 characters that were copied into the OutputString \r
+ buffer, include extra glyph info and '\0' info.\r
\r
**/\r
UINT16\r
GetLineByWidth (\r
IN CHAR16 *InputString,\r
IN UINT16 LineWidth,\r
+ IN OUT UINT16 *GlyphWidth,\r
IN OUT UINTN *Index,\r
OUT CHAR16 **OutputString\r
)\r
{\r
- UINT16 Count;\r
- UINT16 Count2;\r
+ UINT16 StrOffset;\r
+ UINT16 GlyphOffset;\r
+ UINT16 OriginalGlyphWidth;\r
+ BOOLEAN ReturnFlag;\r
+ UINT16 LastSpaceOffset;\r
+ UINT16 LastGlyphWidth;\r
+\r
+ if (InputString == NULL || Index == NULL || OutputString == NULL) {\r
+ return 0;\r
+ }\r
\r
- if (GetLineByWidthFinished) {\r
- GetLineByWidthFinished = FALSE;\r
- return (UINT16) 0;\r
+ if (LineWidth == 0 || *GlyphWidth == 0) {\r
+ return 0;\r
}\r
\r
- Count = LineWidth;\r
- Count2 = 0;\r
+ //\r
+ // Save original glyph width.\r
+ //\r
+ OriginalGlyphWidth = *GlyphWidth;\r
+ LastGlyphWidth = OriginalGlyphWidth;\r
+ ReturnFlag = FALSE;\r
+ LastSpaceOffset = 0;\r
\r
- *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
+ //\r
+ // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.\r
+ // To avoid displaying this empty line in screen, just skip the two CHARs here.\r
+ //\r
+ if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
+ *Index = *Index + 2;\r
+ }\r
\r
//\r
- // Ensure we have got a valid buffer\r
+ // Fast-forward the string and see if there is a carriage-return in the string\r
//\r
- if (*OutputString != NULL) {\r
+ for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {\r
+ switch (InputString[*Index + StrOffset]) {\r
+ case NARROW_CHAR:\r
+ *GlyphWidth = 1;\r
+ break;\r
\r
- //\r
- //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.\r
- //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
- //\r
- if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
- *Index = *Index + 2;\r
- }\r
+ case WIDE_CHAR:\r
+ *GlyphWidth = 2;\r
+ break;\r
\r
- //\r
- // Fast-forward the string and see if there is a carriage-return in the string\r
- //\r
- for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
- ;\r
+ case CHAR_CARRIAGE_RETURN:\r
+ case CHAR_LINEFEED:\r
+ case CHAR_NULL:\r
+ ReturnFlag = TRUE;\r
+ break;\r
\r
+ default:\r
+ GlyphOffset = GlyphOffset + *GlyphWidth;\r
+\r
+ //\r
+ // Record the last space info in this line. Will be used in rewind.\r
+ //\r
+ if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {\r
+ LastSpaceOffset = StrOffset;\r
+ LastGlyphWidth = *GlyphWidth;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if (ReturnFlag) {\r
+ break;\r
+ }\r
+ } \r
+\r
+ //\r
+ // Rewind the string from the maximum size until we see a space to break the line\r
+ //\r
+ if (GlyphOffset > LineWidth) {\r
//\r
- // Copy the desired LineWidth of data to the output buffer.\r
- // Also make sure that we don't copy more than the string.\r
- // Also make sure that if there are linefeeds, we account for them.\r
+ // Rewind the string to last space char in this line.\r
//\r
- if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
- (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
- ) {\r
+ if (LastSpaceOffset != 0) {\r
+ StrOffset = LastSpaceOffset;\r
+ *GlyphWidth = LastGlyphWidth;\r
+ } else {\r
//\r
- // Convert to CHAR16 value and show that we are done with this operation\r
+ // Roll back to last char in the line width.\r
//\r
- LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
- if (LineWidth != 0) {\r
- GetLineByWidthFinished = TRUE;\r
- }\r
- } else {\r
- if (Count2 == LineWidth) {\r
- //\r
- // Rewind the string from the maximum size until we see a space to break the line\r
- //\r
- for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
- ;\r
- if (LineWidth == 0) {\r
- LineWidth = Count;\r
- }\r
- } else {\r
- LineWidth = Count2;\r
- }\r
+ StrOffset--;\r
}\r
+ }\r
+\r
+ //\r
+ // The CHAR_NULL has process last time, this time just return 0 to stand for the end.\r
+ //\r
+ if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Need extra glyph info and '\0' info, so +2.\r
+ //\r
+ *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));\r
+ if (*OutputString == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Save the glyph info at the begin of the string, will used by Print function.\r
+ //\r
+ if (OriginalGlyphWidth == 1) {\r
+ *(*OutputString) = NARROW_CHAR;\r
+ } else {\r
+ *(*OutputString) = WIDE_CHAR;\r
+ }\r
\r
- CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
+ CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));\r
\r
+ if (InputString[*Index + StrOffset] == CHAR_SPACE) {\r
+ //\r
+ // Skip the space info at the begin of next line.\r
+ // \r
+ *Index = (UINT16) (*Index + StrOffset + 1);\r
+ } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
+ //\r
+ // Skip the /n or /n/r info.\r
//\r
- // If currently pointing to a space, increment the index to the first non-space character\r
+ if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
+ *Index = (UINT16) (*Index + StrOffset + 2);\r
+ } else {\r
+ *Index = (UINT16) (*Index + StrOffset + 1);\r
+ }\r
+ } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
//\r
- for (;\r
- (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
- (*Index)++\r
- )\r
- ;\r
- *Index = (UINT16) (*Index + LineWidth);\r
- return LineWidth;\r
+ // Skip the /r or /r/n info.\r
+ // \r
+ if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
+ *Index = (UINT16) (*Index + StrOffset + 2);\r
+ } else {\r
+ *Index = (UINT16) (*Index + StrOffset + 1);\r
+ }\r
} else {\r
- return (UINT16) 0;\r
+ *Index = (UINT16) (*Index + StrOffset);\r
}\r
+\r
+ //\r
+ // Include extra glyph info and '\0' info, so +2.\r
+ //\r
+ return StrOffset + 2;\r
}\r
\r
\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
UINTN OriginalRow;\r
CHAR16 *OutputString;\r
CHAR16 *OptionString;\r
+ UINT16 GlyphWidth;\r
\r
Row = 0;\r
- OptionString = *OptionalString;\r
- OutputString = NULL;\r
-\r
+ OptionString = NULL;\r
+ Width = (UINT16) gOptionBlockWidth;\r
+ OriginalRow = 0;\r
+ GlyphWidth = 1;\r
+ \r
ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+ if (OptionString == NULL) {\r
+ return;\r
+ }\r
\r
- if (OptionString != NULL) {\r
- Width = (UINT16) gOptionBlockWidth;\r
-\r
- OriginalRow = Row;\r
-\r
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\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
+ Row++;\r
//\r
- // If there is more string to process print on the next row and increment the Skip value\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 (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
- }\r
- }\r
-\r
- FreePool (OutputString);\r
- if (SkipValue != 0) {\r
- SkipValue--;\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
- Row = OriginalRow;\r
+ FreePool (OutputString);\r
}\r
\r
- *OptionalString = OptionString;\r
+ if (OptionString != NULL) {\r
+ FreePool (OptionString);\r
+ }\r
}\r
\r
\r
)\r
{\r
LIST_ENTRY *Temp;\r
- UI_MENU_OPTION *MenuOption;\r
\r
Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
\r
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
\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
@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
+\r
**/\r
INTN\r
MoveToNextStatement (\r
+ IN UI_MENU_SELECTION *Selection,\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 (IsSelectable (NextMenuOption)) {\r
- break;\r
+ //\r
+ // NextMenuOption->Row == 0 means this menu has not calculate\r
+ // the NextMenuOption->Skip value yet, just calculate here.\r
+ //\r
+ if (NextMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, NextMenuOption);\r
}\r
- if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
- HitEnd = TRUE;\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
+ }\r
+\r
+ if (IsSelectable (NextMenuOption)) {\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
+ // Arrive at begin of the menu list.\r
//\r
- Distance = 0;\r
- Pos = *CurrentPosition;\r
+ if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
+ Distance = -1;\r
+ break;\r
+ }\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
+ // 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
- Distance -= NextMenuOption->Skip;\r
- Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+\r
+ Distance += NextMenuOption->Skip;\r
}\r
+\r
+ PreMenuOption = NextMenuOption;\r
+ Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
}\r
\r
*CurrentPosition = &NextMenuOption->Link;\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
+ @param Statement The statement belong to goto op code.\r
+ @param Selection The selection info.\r
+ @param Repaint Whether need to repaint the menu.\r
+ @param NewLine Whether need to create new line.\r
+\r
+ @retval EFI_SUCCESS The menu process successfully.\r
+ @return Other value if the process failed.\r
+**/\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+ IN OUT FORM_BROWSER_STATEMENT *Statement,\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ OUT BOOLEAN *Repaint,\r
+ OUT BOOLEAN *NewLine\r
+ )\r
+{\r
+ CHAR16 *StringPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ FORM_BROWSER_FORM *RefForm;\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
+ StringPtr = NULL;\r
+\r
+ //\r
+ // Prepare the device path check, get the device path info first.\r
+ //\r
+ if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+ StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+ }\r
+\r
+ //\r
+ // Check whether the device path string is a valid string.\r
+ //\r
+ if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Goto another Hii Package list\r
+ //\r
+ if (mPathFromText != NULL) {\r
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+ if (DevicePath != NULL) {\r
+ Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+ FreePool (DevicePath);\r
+ }\r
+ FreePool (StringPtr);\r
+ } else {\r
+ //\r
+ // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+ //\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gProtocolNotFound, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ FreePool (StringPtr);\r
+ return Status;\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\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
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ } \r
+ //\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
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+ //\r
+ // Check whether target From is suppressed.\r
+ //\r
+ RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+\r
+ if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+ if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+ //\r
+ // Form is suppressed. \r
+ //\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Goto another form inside this formset,\r
+ //\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\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
+ //\r
+ // Goto another Question\r
+ //\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+\r
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ } else {\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ if (NewLine != NULL) {\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
+\r
/**\r
Display menu and wait for user to select one menu option, then return it.\r
If AutoBoot is enabled, then if user doesn't select any option,\r
{\r
INTN SkipValue;\r
INTN Difference;\r
- INTN OldSkipValue;\r
UINTN DistanceValue;\r
UINTN Row;\r
UINTN Col;\r
UINTN BottomRow;\r
UINTN OriginalRow;\r
UINTN Index;\r
- UINT32 Count;\r
UINT16 Width;\r
CHAR16 *StringPtr;\r
CHAR16 *OptionString;\r
CHAR16 *OutputString;\r
- CHAR16 *FormattedString;\r
- CHAR16 YesResponse;\r
- CHAR16 NoResponse;\r
+ CHAR16 *HelpString;\r
+ CHAR16 *HelpHeaderString;\r
+ CHAR16 *HelpBottomString;\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
UI_CONTROL_FLAG ControlFlag;\r
EFI_SCREEN_DESCRIPTOR LocalScreen;\r
MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
+ MENU_REFRESH_ENTRY *MenuUpdateEntry; \r
UI_SCREEN_OPERATION ScreenOperation;\r
UINT8 MinRefreshInterval;\r
- UINTN BufferSize;\r
UINT16 DefaultId;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
FORM_BROWSER_STATEMENT *Statement;\r
- CHAR16 TemStr[2];\r
- UINT8 *DevicePathBuffer;\r
- UINT8 DigitUint8;\r
UI_MENU_LIST *CurrentMenu;\r
- UI_MENU_LIST *MenuList;\r
- FORM_BROWSER_FORM *RefForm;\r
+ UINTN ModalSkipColumn;\r
+ BROWSER_HOT_KEY *HotKey;\r
+ UINTN HelpPageIndex;\r
+ UINTN HelpPageCount;\r
+ UINTN RowCount;\r
+ UINTN HelpLine;\r
+ UINTN HelpHeaderLine;\r
+ UINTN HelpBottomLine;\r
+ BOOLEAN MultiHelpPage;\r
+ UINT16 GlyphWidth;\r
+ UINT16 EachLineWidth;\r
+ UINT16 HeaderLineWidth;\r
+ UINT16 BottomLineWidth;\r
\r
CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
\r
Status = EFI_SUCCESS;\r
- FormattedString = NULL;\r
+ HelpString = NULL;\r
+ HelpHeaderString = NULL;\r
+ HelpBottomString = NULL;\r
OptionString = NULL;\r
ScreenOperation = UiNoOperation;\r
NewLine = TRUE;\r
MinRefreshInterval = 0;\r
DefaultId = 0;\r
-\r
+ HelpPageCount = 0;\r
+ HelpLine = 0;\r
+ RowCount = 0;\r
+ HelpBottomLine = 0;\r
+ HelpHeaderLine = 0;\r
+ HelpPageIndex = 0;\r
+ MultiHelpPage = FALSE;\r
+ EachLineWidth = 0;\r
+ HeaderLineWidth = 0;\r
+ BottomLineWidth = 0;\r
OutputString = NULL;\r
UpArrow = FALSE;\r
DownArrow = FALSE;\r
SkipValue = 0;\r
- OldSkipValue = 0;\r
MenuRefreshEntry = gMenuRefreshHead;\r
\r
NextMenuOption = NULL;\r
PreviousMenuOption = NULL;\r
SavedMenuOption = NULL;\r
- RefForm = NULL;\r
+ HotKey = NULL;\r
+ ModalSkipColumn = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6;\r
\r
ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
\r
Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
}\r
\r
- Col = LocalScreen.LeftColumn;\r
- BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+ if (Selection->Form->ModalForm) {\r
+ Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
+ } else {\r
+ Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
+ }\r
+\r
+ BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1;\r
\r
Selection->TopRow = TopRow;\r
Selection->BottomRow = BottomRow;\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
\r
if (Selection->QuestionId == 0) {\r
//\r
// Highlight not specified, fetch it from cached menu\r
//\r
Selection->QuestionId = CurrentMenu->QuestionId;\r
+ Selection->Sequence = CurrentMenu->Sequence;\r
}\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
UpArrow = FALSE;\r
Row = TopRow;\r
\r
- Temp = SkipValue;\r
- Temp2 = SkipValue;\r
-\r
- ClearLines (\r
- LocalScreen.LeftColumn,\r
- LocalScreen.RightColumn,\r
- TopRow - SCROLL_ARROW_HEIGHT,\r
- BottomRow + SCROLL_ARROW_HEIGHT,\r
- FIELD_TEXT | FIELD_BACKGROUND\r
- );\r
+ Temp = (UINTN) SkipValue;\r
+ Temp2 = (UINTN) SkipValue;\r
\r
+ //\r
+ // 1. Clear the screen.\r
+ //\r
+ if (Selection->Form->ModalForm) {\r
+ ClearLines (\r
+ LocalScreen.LeftColumn + ModalSkipColumn,\r
+ LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+ TopRow - SCROLL_ARROW_HEIGHT,\r
+ BottomRow + SCROLL_ARROW_HEIGHT,\r
+ PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+ ); \r
+ } else {\r
+ ClearLines (\r
+ LocalScreen.LeftColumn,\r
+ LocalScreen.RightColumn,\r
+ TopRow - SCROLL_ARROW_HEIGHT,\r
+ BottomRow + SCROLL_ARROW_HEIGHT,\r
+ PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+ );\r
+ }\r
UiFreeRefreshList ();\r
MinRefreshInterval = 0;\r
\r
+ //\r
+ // 2.Paint the menu.\r
+ //\r
for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
MenuOption = MENU_OPTION_FROM_LINK (Link);\r
MenuOption->Row = Row;\r
MenuOption->Col = Col;\r
- MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+ if (Selection->Form->ModalForm) {\r
+ MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn;\r
+ } else {\r
+ MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+ }\r
\r
Statement = MenuOption->ThisTag;\r
if (Statement->InSubtitle) {\r
gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
} else {\r
if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
- gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
}\r
}\r
\r
Width = GetWidth (Statement, MenuOption->Handle);\r
OriginalRow = Row;\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+ if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
+ //\r
+ // Print Arrow for Goto button.\r
+ //\r
+ PrintAt (\r
+ MenuOption->Col - 2,\r
+ Row,\r
+ L"%c",\r
+ GEOMETRICSHAPE_RIGHT_TRIANGLE\r
+ );\r
+ }\r
+\r
+ //\r
+ // 2.1. Paint the description.\r
+ //\r
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+ //\r
+ // Temp means need to skip how many lines from the start.\r
+ //\r
if ((Temp == 0) && (Row <= BottomRow)) {\r
PrintStringAt (MenuOption->Col, Row, OutputString);\r
}\r
Temp = 0;\r
Row = OriginalRow;\r
\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ //\r
+ // 2.2. Paint the option string.\r
+ //\r
Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
if (EFI_ERROR (Status)) {\r
//\r
\r
if (OptionString != NULL) {\r
if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
- //\r
- // If leading spaces on OptionString - remove the spaces\r
- //\r
- for (Index = 0; OptionString[Index] == L' '; Index++) {\r
- MenuOption->OptCol++;\r
- }\r
-\r
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
- OptionString[Count] = OptionString[Index];\r
- Count++;\r
- }\r
-\r
- OptionString[Count] = CHAR_NULL;\r
- }\r
-\r
- //\r
- // If Question request refresh, register the op-code\r
- //\r
- if (Statement->RefreshInterval != 0) {\r
- //\r
- // Menu will be refreshed at minimal interval of all Questions\r
- // which have refresh request\r
- //\r
- if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
- MinRefreshInterval = Statement->RefreshInterval;\r
- }\r
-\r
- if (gMenuRefreshHead == NULL) {\r
- MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
- ASSERT (MenuRefreshEntry != NULL);\r
- MenuRefreshEntry->MenuOption = MenuOption;\r
- MenuRefreshEntry->Selection = Selection;\r
- MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
- MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
- gMenuRefreshHead = MenuRefreshEntry;\r
- } else {\r
- //\r
- // Advance to the last entry\r
- //\r
- for (MenuRefreshEntry = gMenuRefreshHead;\r
- MenuRefreshEntry->Next != NULL;\r
- MenuRefreshEntry = MenuRefreshEntry->Next\r
- )\r
- ;\r
- MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
- ASSERT (MenuRefreshEntry->Next != NULL);\r
- MenuRefreshEntry = MenuRefreshEntry->Next;\r
- MenuRefreshEntry->MenuOption = MenuOption;\r
- MenuRefreshEntry->Selection = Selection;\r
- MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
- MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
- }\r
+ ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
}\r
\r
Width = (UINT16) gOptionBlockWidth;\r
OriginalRow = Row;\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
if ((Temp2 == 0) && (Row <= BottomRow)) {\r
PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
}\r
\r
FreePool (OptionString);\r
}\r
+\r
+ //\r
+ // 2.4 Special process for Test opcode with test two.\r
+ //\r
+ if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
+ if (gMenuEventGuidRefreshHead == NULL) {\r
+ MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+ gMenuEventGuidRefreshHead = MenuUpdateEntry;\r
+ } else {\r
+ MenuUpdateEntry = gMenuEventGuidRefreshHead;\r
+ while (MenuUpdateEntry->Next != NULL) {\r
+ MenuUpdateEntry = MenuUpdateEntry->Next; \r
+ }\r
+ MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+ MenuUpdateEntry = MenuUpdateEntry->Next; \r
+ }\r
+ ASSERT (MenuUpdateEntry != NULL);\r
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event);\r
+ ASSERT (!EFI_ERROR (Status));\r
+ MenuUpdateEntry->MenuOption = MenuOption;\r
+ MenuUpdateEntry->Selection = Selection;\r
+ MenuUpdateEntry->CurrentColumn = MenuOption->OptCol;\r
+ MenuUpdateEntry->CurrentRow = MenuOption->Row;\r
+ if (MenuOption->GrayOut) {\r
+ MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+ } else {\r
+ MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // If Question request refresh, register the op-code\r
+ //\r
+ if (Statement->RefreshInterval != 0) {\r
+ //\r
+ // Menu will be refreshed at minimal interval of all Questions\r
+ // which have refresh request\r
+ //\r
+ if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
+ MinRefreshInterval = Statement->RefreshInterval;\r
+ }\r
+ \r
+ if (gMenuRefreshHead == NULL) {\r
+ MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+ gMenuRefreshHead = MenuRefreshEntry;\r
+ } else {\r
+ MenuRefreshEntry = gMenuRefreshHead;\r
+ while (MenuRefreshEntry->Next != NULL) {\r
+ MenuRefreshEntry = MenuRefreshEntry->Next; \r
+ }\r
+ MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+ MenuRefreshEntry = MenuRefreshEntry->Next;\r
+ }\r
+ ASSERT (MenuRefreshEntry != NULL); \r
+ MenuRefreshEntry->MenuOption = MenuOption;\r
+ MenuRefreshEntry->Selection = Selection;\r
+ MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
+ MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
+ if (MenuOption->GrayOut) {\r
+ MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+ } else { \r
+ MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+ }\r
+ }\r
+ \r
//\r
// If this is a text op with secondary text information\r
//\r
\r
Width = (UINT16) gOptionBlockWidth;\r
OriginalRow = Row;\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
+ for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
if ((Temp == 0) && (Row <= BottomRow)) {\r
PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
}\r
Row = OriginalRow;\r
FreePool (StringPtr);\r
}\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
\r
//\r
- // Need to handle the bottom of the display\r
+ // 3. Update the row info which will be used by next menu.\r
//\r
- if (MenuOption->Skip > 1) {\r
+ if (Link == TopOfScreen) {\r
Row += MenuOption->Skip - SkipValue;\r
- SkipValue = 0;\r
} else {\r
Row += MenuOption->Skip;\r
}\r
L"%c",\r
ARROW_UP\r
);\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
}\r
\r
if (DownArrow) {\r
L"%c",\r
ARROW_DOWN\r
);\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
}\r
\r
MenuOption = NULL;\r
// NewPos: Current menu option that need to hilight\r
//\r
ControlFlag = CfUpdateHelpString;\r
+ if (TopOfScreen == &MenuOption->Link) {\r
+ Temp = SkipValue;\r
+ } else {\r
+ Temp = 0;\r
+ }\r
+ if (NewPos == TopOfScreen) {\r
+ Temp2 = SkipValue;\r
+ } else {\r
+ Temp2 = 0;\r
+ }\r
+ if (InitializedFlag) {\r
+ InitializedFlag = FALSE;\r
+ MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+ }\r
\r
//\r
// Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
NewPos = gMenuOption.ForwardLink;\r
SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
\r
- while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &gMenuOption) {\r
+ while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId ||\r
+ SavedMenuOption->Sequence != Selection->Sequence) &&\r
+ NewPos->ForwardLink != &gMenuOption) {\r
NewPos = NewPos->ForwardLink;\r
SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\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 -= SkipValue;\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
+ //\r
+ // Not find the selected menu in current show page.\r
+ // Have two case to enter this if:\r
+ // 1. Not find the menu at current page.\r
+ // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
+ // For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
+ //\r
+ // Base on the selected menu will show at the bottom of the page,\r
+ // select the menu which will show at the top of the page.\r
+ //\r
+ if (Link != NewPos || Index > BottomRow || \r
+ (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\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
+ //\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; Index <= BottomRow; ) {\r
+ for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) { \r
Link = Link->BackLink;\r
SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
- Index += SavedMenuOption->Skip;\r
+ if (SavedMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+ }\r
+ Index += 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
+ } else {\r
+ //\r
+ // Check whether need to skip some line for menu shows at the top of the page.\r
+ //\r
+ SkipValue = Index - BottomRow - 1;\r
+ if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+ TopOfScreen = Link;\r
+ } else {\r
+ SkipValue = 0;\r
+ TopOfScreen = Link->ForwardLink;\r
+ }\r
}\r
- TopOfScreen = Link->ForwardLink;\r
\r
Repaint = TRUE;\r
NewLine = TRUE;\r
//\r
gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
if (OptionString != NULL) {\r
if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
(MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
) {\r
- //\r
- // If leading spaces on OptionString - remove the spaces\r
- //\r
- for (Index = 0; OptionString[Index] == L' '; Index++)\r
- ;\r
-\r
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
- OptionString[Count] = OptionString[Index];\r
- Count++;\r
- }\r
-\r
- OptionString[Count] = CHAR_NULL;\r
+ ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
}\r
\r
Width = (UINT16) gOptionBlockWidth;\r
OriginalRow = MenuOption->Row;\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
- MenuOption->Row++;\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
if (MenuOption->GrayOut) {\r
gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
} else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
- gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
}\r
\r
OriginalRow = MenuOption->Row;\r
Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
- MenuOption->Row++;\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, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
}\r
}\r
}\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
CurrentMenu->QuestionId = Statement->QuestionId;\r
+ CurrentMenu->Sequence = MenuOption->Sequence;\r
\r
//\r
// Set reverse attribute\r
//\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
\r
//\r
//\r
if (gMenuRefreshHead != NULL) {\r
for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
+ if (MenuRefreshEntry->MenuOption->GrayOut) {\r
+ MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+ } else { \r
+ MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+ }\r
if (MenuRefreshEntry->MenuOption == MenuOption) {\r
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
+ MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\r
}\r
}\r
}\r
ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
if (OptionString != NULL) {\r
if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
- //\r
- // If leading spaces on OptionString - remove the spaces\r
- //\r
- for (Index = 0; OptionString[Index] == L' '; Index++)\r
- ;\r
-\r
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
- OptionString[Count] = OptionString[Index];\r
- Count++;\r
- }\r
-\r
- OptionString[Count] = CHAR_NULL;\r
+ ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
}\r
Width = (UINT16) gOptionBlockWidth;\r
\r
OriginalRow = MenuOption->Row;\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
OriginalRow = MenuOption->Row;\r
\r
Width = GetWidth (Statement, MenuOption->Handle);\r
+ GlyphWidth = 1;\r
\r
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\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
- MenuOption->Row++;\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
// Clear reverse attribute\r
//\r
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
}\r
//\r
// Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
\r
case CfUpdateHelpString:\r
ControlFlag = CfPrepareToReadKey;\r
+ if (Selection->Form->ModalForm) {\r
+ break;\r
+ }\r
\r
- if (Repaint || NewLine) {\r
+ if (Repaint || NewLine) {\r
//\r
// Don't print anything if it is a NULL help token\r
//\r
- if (MenuOption->ThisTag->Help == 0) {\r
+ ASSERT(MenuOption != NULL);\r
+ if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
StringPtr = L"\0";\r
} else {\r
StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
}\r
\r
- ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
-\r
- gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
-\r
- for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
+ RowCount = BottomRow - TopRow;\r
+ HelpPageIndex = 0;\r
+ //\r
+ // 1.Calculate how many line the help string need to print.\r
+ //\r
+ if (HelpString != NULL) {\r
+ FreePool (HelpString);\r
+ }\r
+ HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);\r
+ if (HelpLine > RowCount) {\r
+ MultiHelpPage = TRUE;\r
+ StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
+ if (HelpHeaderString != NULL) {\r
+ FreePool (HelpHeaderString);\r
+ }\r
+ HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, RowCount);\r
+ StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
+ if (HelpBottomString != NULL) {\r
+ FreePool (HelpBottomString);\r
+ }\r
+ HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, RowCount);\r
//\r
- // Pad String with spaces to simulate a clearing of the previous line\r
+ // Calculate the help page count.\r
//\r
- for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
- StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
+ if (HelpLine > 2 * RowCount - 2) {\r
+ HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
+ if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
+ HelpPageCount += 1;\r
+ }\r
+ } else {\r
+ HelpPageCount = 2;\r
}\r
+ } else {\r
+ MultiHelpPage = FALSE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Clean the help field first.\r
+ //\r
+ ClearLines (\r
+ LocalScreen.RightColumn - gHelpBlockWidth,\r
+ LocalScreen.RightColumn,\r
+ TopRow,\r
+ BottomRow,\r
+ PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+ );\r
+\r
+ //\r
+ // Check whether need to show the 'More(U/u)' at the begin.\r
+ // Base on current direct info, here shows aligned to the right side of the column.\r
+ // If the direction is multi line and aligned to right side may have problem, so \r
+ // add ASSERT code here.\r
+ //\r
+ if (HelpPageIndex > 0) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+ for (Index = 0; Index < HelpHeaderLine; Index++) {\r
+ ASSERT (HelpHeaderLine == 1);\r
+ ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
+ PrintStringAt (\r
+ LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
+ Index + TopRow,\r
+ &HelpHeaderString[Index * HeaderLineWidth]\r
+ );\r
+ }\r
+ }\r
\r
+ gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
+ //\r
+ // Print the help string info.\r
+ //\r
+ if (!MultiHelpPage) {\r
+ for (Index = 0; Index < HelpLine; Index++) {\r
PrintStringAt (\r
LocalScreen.RightColumn - gHelpBlockWidth,\r
Index + TopRow,\r
- &FormattedString[Index * gHelpBlockWidth * 2]\r
+ &HelpString[Index * EachLineWidth]\r
+ );\r
+ }\r
+ gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+ } else {\r
+ if (HelpPageIndex == 0) {\r
+ for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
+ PrintStringAt (\r
+ LocalScreen.RightColumn - gHelpBlockWidth,\r
+ Index + TopRow,\r
+ &HelpString[Index * EachLineWidth]\r
+ );\r
+ }\r
+ } else {\r
+ for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
+ (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
+ PrintStringAt (\r
+ LocalScreen.RightColumn - gHelpBlockWidth,\r
+ Index + TopRow + HelpHeaderLine,\r
+ &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth]\r
+ );\r
+ }\r
+ if (HelpPageIndex == HelpPageCount - 1) {\r
+ gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+ }\r
+ } \r
+ }\r
+\r
+ //\r
+ // Check whether need to print the 'More(D/d)' at the bottom.\r
+ // Base on current direct info, here shows aligned to the right side of the column.\r
+ // If the direction is multi line and aligned to right side may have problem, so \r
+ // add ASSERT code here.\r
+ //\r
+ if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+ for (Index = 0; Index < HelpBottomLine; Index++) {\r
+ ASSERT (HelpBottomLine == 1);\r
+ ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
+ PrintStringAt (\r
+ LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
+ Index + BottomRow - HelpBottomLine,\r
+ &HelpBottomString[Index * BottomLineWidth]\r
);\r
}\r
}\r
//\r
// Wait for user's selection\r
//\r
- do {\r
- Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
- } while (Status == EFI_TIMEOUT);\r
+ while (TRUE) {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
\r
- if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
//\r
- // IFR is updated in Callback of refresh opcode, re-parse it\r
+ // If we encounter error, continue to read another key in.\r
//\r
- Selection->Statement = NULL;\r
- return EFI_SUCCESS;\r
+ if (Status != EFI_NOT_READY) {\r
+ continue;\r
+ }\r
+\r
+ Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
+ //\r
+ // IFR is updated in Callback of refresh opcode, re-parse it\r
+ //\r
+ ControlFlag = CfCheckSelection;\r
+ Selection->Statement = NULL;\r
+ break;\r
+ }\r
}\r
\r
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
- //\r
- // If we encounter error, continue to read another key in.\r
- //\r
- if (EFI_ERROR (Status)) {\r
- ControlFlag = CfReadKey;\r
+ if (ControlFlag == CfCheckSelection) {\r
break;\r
}\r
\r
switch (Key.UnicodeChar) {\r
case CHAR_CARRIAGE_RETURN:\r
+ if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+ ControlFlag = CfReadKey;\r
+ break;\r
+ }\r
+\r
ScreenOperation = UiSelect;\r
gDirection = 0;\r
break;\r
//\r
case '+':\r
case '-':\r
+ //\r
+ // If the screen has no menu items, and the user didn't select UiReset\r
+ // ignore the selection and go back to reading keys.\r
+ //\r
+ if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+ ControlFlag = CfReadKey;\r
+ break;\r
+ }\r
+\r
+ ASSERT(MenuOption != NULL);\r
Statement = MenuOption->ThisTag;\r
if ((Statement->Operand == EFI_IFR_DATE_OP)\r
|| (Statement->Operand == EFI_IFR_TIME_OP)\r
//\r
Repaint = TRUE;\r
NewLine = TRUE;\r
+ } else {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
}\r
if (OptionString != NULL) {\r
FreePool (OptionString);\r
\r
case ' ':\r
if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
- if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+ //\r
+ // If the screen has no menu items, and the user didn't select UiReset\r
+ // ignore the selection and go back to reading keys.\r
+ //\r
+ if(IsListEmpty (&gMenuOption)) {\r
+ ControlFlag = CfReadKey;\r
+ break;\r
+ }\r
+ \r
+ ASSERT(MenuOption != NULL);\r
+ if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
ScreenOperation = UiSelect;\r
}\r
}\r
break;\r
\r
+ case 'D':\r
+ case 'd':\r
+ if (!MultiHelpPage) {\r
+ ControlFlag = CfReadKey;\r
+ break;\r
+ }\r
+ ControlFlag = CfUpdateHelpString;\r
+ HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
+ break;\r
+\r
+ case 'U':\r
+ case 'u':\r
+ if (!MultiHelpPage) {\r
+ ControlFlag = CfReadKey;\r
+ break;\r
+ }\r
+ ControlFlag = CfUpdateHelpString;\r
+ HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
+ break;\r
+\r
case CHAR_NULL:\r
- if (((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
- ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
- ) {\r
+ for (Index = 0; Index < mScanCodeNumber; Index++) {\r
+ if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
+ ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
//\r
- // If the function key has been disabled, just ignore the key.\r
+ // ModalForm has no ESC key and Hot Key.\r
//\r
- } else {\r
- for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
- if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
- if (Key.ScanCode == SCAN_F9) {\r
- //\r
- // Reset to standard default\r
- //\r
- DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
- }\r
- ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
- break;\r
- }\r
+ ControlFlag = CfReadKey;\r
+ } else if (Index == mScanCodeNumber) {\r
+ //\r
+ // Check whether Key matches the registered hot key.\r
+ //\r
+ HotKey = NULL;\r
+ if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
+ HotKey = GetHotKeyFromRegisterList (&Key);\r
+ }\r
+ if (HotKey != NULL) {\r
+ ScreenOperation = UiHotKey;\r
}\r
}\r
break;\r
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
case CfUiSelect:\r
ControlFlag = CfCheckSelection;\r
\r
+ ASSERT(MenuOption != NULL);\r
Statement = MenuOption->ThisTag;\r
- if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
- (Statement->Operand == EFI_IFR_DATE_OP) ||\r
- (Statement->Operand == EFI_IFR_TIME_OP) ||\r
- (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
+ if (Statement->Operand == EFI_IFR_TEXT_OP) {\r
break;\r
}\r
\r
\r
switch (Statement->Operand) {\r
case EFI_IFR_REF_OP:\r
- if (Statement->RefDevicePath != 0) {\r
- //\r
- // Goto another Hii Package list\r
- //\r
- Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
- StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
- if (StringPtr == NULL) {\r
- //\r
- // No device path string not found, exit\r
- //\r
- Selection->Action = UI_ACTION_EXIT;\r
- Selection->Statement = NULL;\r
- break;\r
- }\r
- BufferSize = StrLen (StringPtr) / 2;\r
- DevicePath = AllocatePool (BufferSize);\r
-\r
- //\r
- // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
- //\r
- DevicePathBuffer = (UINT8 *) DevicePath;\r
- for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
- TemStr[0] = StringPtr[Index];\r
- DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
- if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
- //\r
- // Invalid Hex Char as the tail.\r
- //\r
- break;\r
- }\r
- if ((Index & 1) == 0) {\r
- DevicePathBuffer [Index/2] = DigitUint8;\r
- } else {\r
- DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
- }\r
- }\r
-\r
- Selection->Handle = DevicePathToHiiHandle (DevicePath);\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
- break;\r
- }\r
-\r
- FreePool (StringPtr);\r
- FreePool (DevicePath);\r
-\r
- CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
- Selection->FormId = Statement->RefFormId;\r
- Selection->QuestionId = Statement->RefQuestionId;\r
- } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
- //\r
- // Goto another Formset, check for uncommitted data\r
- //\r
- Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
- CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
- Selection->FormId = Statement->RefFormId;\r
- Selection->QuestionId = Statement->RefQuestionId;\r
- } else if (Statement->RefFormId != 0) {\r
- //\r
- // Check whether target From is suppressed.\r
- //\r
- RefForm = IdToForm (Selection->FormSet, Statement->RefFormId);\r
-\r
- if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
- Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (RefForm->SuppressExpression->Result.Value.b) {\r
- //\r
- // Form is suppressed. \r
- //\r
- do {\r
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-\r
- Repaint = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Goto another form inside this formset,\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->RefFormId);\r
- if (MenuList == NULL) {\r
- MenuList = UiAddMenuList (CurrentMenu, &Selection->FormSetGuid, Statement->RefFormId);\r
- }\r
-\r
- Selection->FormId = Statement->RefFormId;\r
- Selection->QuestionId = Statement->RefQuestionId;\r
- } else if (Statement->RefQuestionId != 0) {\r
- //\r
- // Goto another Question\r
- //\r
- Selection->QuestionId = Statement->RefQuestionId;\r
-\r
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
- Selection->Action = UI_ACTION_REFRESH_FORM;\r
- } else {\r
- Repaint = TRUE;\r
- NewLine = TRUE;\r
- break;\r
- }\r
- }\r
+ ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
break;\r
\r
case EFI_IFR_ACTION_OP:\r
// 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
+ FindNextMenu (Selection, &Repaint, &NewLine);\r
+ break;\r
\r
case CfUiLeft:\r
ControlFlag = CfCheckSelection;\r
+ ASSERT(MenuOption != NULL);\r
if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
if (MenuOption->Sequence != 0) {\r
//\r
// In the middle or tail of the Date/Time op-code set, go left.\r
//\r
+ ASSERT(NewPos != NULL);\r
NewPos = NewPos->BackLink;\r
}\r
}\r
\r
case CfUiRight:\r
ControlFlag = CfCheckSelection;\r
+ ASSERT(MenuOption != NULL);\r
if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
if (MenuOption->Sequence != 2) {\r
//\r
// In the middle or tail of the Date/Time op-code set, go left.\r
//\r
+ ASSERT(NewPos != NULL);\r
NewPos = NewPos->ForwardLink;\r
}\r
}\r
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
+ ASSERT (MenuOption != NULL);\r
+ NewLine = TRUE;\r
+ NewPos = NewPos->BackLink;\r
\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
- //\r
- // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
- // don't worry about a redraw.\r
- //\r
- if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
- Repaint = TRUE;\r
- TopOfScreen = NewPos;\r
+ if (PreviousMenuOption->Row == 0) {\r
+ UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
}\r
-\r
- Difference = MoveToNextStatement (TRUE, &NewPos);\r
- PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
- DistanceValue += PreviousMenuOption->Skip;\r
-\r
- if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
- if (Difference > 0) {\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
- OldSkipValue = 0;\r
- }\r
+ DistanceValue = PreviousMenuOption->Skip;\r
+ Difference = 0;\r
+ if (MenuOption->Row >= DistanceValue + TopRow) {\r
+ Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
}\r
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ \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 (MenuOption->Row < TopRow + DistanceValue + Difference) {\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
}\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
case CfUiPageUp:\r
+ //\r
+ // SkipValue means lines is skipped when show the top menu option.\r
+ //\r
ControlFlag = CfCheckSelection;\r
\r
+ ASSERT(NewPos != NULL);\r
+ //\r
+ // Already at the first menu option, so do nothing.\r
+ //\r
if (NewPos->BackLink == &gMenuOption) {\r
NewLine = FALSE;\r
Repaint = FALSE;\r
\r
NewLine = TRUE;\r
Repaint = TRUE;\r
+\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
+ //\r
+ if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {\r
+ SkipValue -= BottomRow - TopRow + 1;\r
+ break;\r
+ }\r
+\r
Link = TopOfScreen;\r
- PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
- Index = BottomRow;\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
- Index = Index - PreviousMenuOption->Skip;\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
+ break;\r
+ }\r
+ Index = Index - PreviousMenuOption->Skip;\r
}\r
+ \r
+ if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
+ SkipValue = 0;\r
+ if (TopOfScreen == &gMenuOption) {\r
+ TopOfScreen = gMenuOption.ForwardLink;\r
+ NewPos = gMenuOption.BackLink;\r
+ MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+ Repaint = FALSE;\r
+ } else if (TopOfScreen != Link) {\r
+ TopOfScreen = Link;\r
+ NewPos = Link;\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 (Selection, FALSE, &NewPos, BottomRow - TopRow);\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 {\r
+ SkipValue = PreviousMenuOption->Skip - (TopRow - Index);\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 (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+ } else {\r
+ NewPos = Link;\r
+ MoveToNextStatement (Selection, 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
break;\r
\r
case CfUiPageDown:\r
+ //\r
+ // SkipValue means lines is skipped when show the top menu option.\r
+ //\r
ControlFlag = CfCheckSelection;\r
\r
+ ASSERT (NewPos != NULL);\r
if (NewPos->ForwardLink == &gMenuOption) {\r
NewLine = FALSE;\r
Repaint = FALSE;\r
Repaint = TRUE;\r
Link = TopOfScreen;\r
NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
- Index = TopRow;\r
- while ((Index <= BottomRow) && (Link->ForwardLink != &gMenuOption)) {\r
- Index = Index + NextMenuOption->Skip;\r
+ Index = TopRow + NextMenuOption->Skip - SkipValue;\r
+ //\r
+ // Count to the menu option which will show at the top of the next form.\r
+ //\r
+ while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {\r
Link = Link->ForwardLink;\r
NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ Index = Index + NextMenuOption->Skip;\r
}\r
\r
- Index += MoveToNextStatement (FALSE, &Link);\r
- if (Index > BottomRow) {\r
+ if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
//\r
- // There are more MenuOption needing scrolling\r
+ // Finally we know that NewPos is the last MenuOption can be focused.\r
//\r
+ Repaint = FALSE;\r
+ MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
+ SkipValue = 0;\r
+ } else {\r
+ //\r
+ // Calculate the skip line for top of screen menu.\r
+ //\r
+ if (Link == TopOfScreen) {\r
+ //\r
+ // The top of screen menu option occupies the entire form.\r
+ //\r
+ SkipValue += BottomRow - TopRow + 1;\r
+ } else {\r
+ SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
+ }\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 Next selectable menu.\r
//\r
- NewLine = FALSE;\r
- Repaint = FALSE;\r
- } else {\r
- NewPos = Link;\r
+ MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
}\r
\r
+ //\r
+ // Save the menu as the next highlight menu.\r
+ //\r
+ NewPos = Link;\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
break;\r
\r
case CfUiDown:\r
+ //\r
+ // SkipValue means lines is skipped when show the top menu option.\r
+ // NewPos points to the menu which is highlighted now.\r
+ //\r
ControlFlag = CfCheckSelection;\r
//\r
// Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
// 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
- NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
\r
- DistanceValue += NextMenuOption->Skip;\r
- DistanceValue += MoveToNextStatement (FALSE, &NewPos);\r
+ Difference = 0;\r
//\r
- // An option might be multi-line, so we need to reflect that data in the overall skip value\r
+ // Current menu not at the bottom of the form.\r
//\r
- UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
+ if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
+ //\r
+ // Find the next selectable menu.\r
+ //\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
+ //\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 (Selection, FALSE, &NewPos, BottomRow - TopRow);\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 (Selection, NextMenuOption);\r
+ }\r
+ DistanceValue = Difference + NextMenuOption->Skip;\r
\r
Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\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) || (MenuOption->Skip > 1)) {\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 - OldSkipValue)) {\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 - OldSkipValue);\r
-\r
- OldSkipValue = Difference;\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
- for (;\r
- Difference >= (INTN) SavedMenuOption->Skip;\r
- Difference = Difference - (INTN) SavedMenuOption->Skip\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
- if (Difference < (INTN) SavedMenuOption->Skip) {\r
- Difference = SavedMenuOption->Skip - Difference - 1;\r
- break;\r
- } else {\r
- if (Difference == (INTN) SavedMenuOption->Skip) {\r
- TopOfScreen = TopOfScreen->ForwardLink;\r
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
- Difference = SavedMenuOption->Skip - Difference;\r
- break;\r
- }\r
- }\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
-\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 = OldSkipValue + (Temp - BottomRow) - 1;\r
+ SkipValue += (Temp - BottomRow) - 1;\r
}\r
} else {\r
- if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+ if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
TopOfScreen = TopOfScreen->ForwardLink;\r
break;\r
- } else {\r
- SkipValue = OldSkipValue;\r
}\r
}\r
//\r
} else {\r
SkipValue++;\r
}\r
+ } else if (SavedMenuOption->Skip == 1) {\r
+ SkipValue = 0;\r
} else {\r
SkipValue = 0;\r
TopOfScreen = TopOfScreen->ForwardLink;\r
} while (SavedMenuOption->Skip == 0);\r
\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
+ // Scroll to the first page.\r
+ //\r
+ if (TopOfScreen != gMenuOption.ForwardLink) {\r
+ TopOfScreen = gMenuOption.ForwardLink;\r
+ Repaint = TRUE;\r
+ MenuOption = NULL;\r
+ } else {\r
//\r
- // If we are at the end of the list and sitting on a text op, we need to more forward\r
+ // Need to remove the current highlight menu.\r
+ // MenuOption saved the last highlight menu info.\r
//\r
- ScreenOperation = UiUp;\r
- ControlFlag = CfScreenOperation;\r
- break;\r
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
}\r
\r
- MenuOption = SavedMenuOption;\r
+ SkipValue = 0;\r
+ NewLine = TRUE;\r
//\r
- // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+ // Get the next highlight menu.\r
//\r
- AdjustDateAndTimePosition (TRUE, &NewPos);\r
+ NewPos = gMenuOption.ForwardLink;\r
+ MoveToNextStatement (Selection, 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
+ case CfUiHotKey:\r
ControlFlag = CfCheckSelection;\r
-\r
+ \r
+ Status = EFI_SUCCESS;\r
//\r
- // Submit the form\r
+ // Discard changes. After it, no NV flag is showed.\r
//\r
- Status = SubmitForm (Selection->FormSet, Selection->Form);\r
-\r
- if (!EFI_ERROR (Status)) {\r
- UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
- UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
- } else {\r
- do {\r
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+ Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+ if (!EFI_ERROR (Status)) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ Selection->Statement = NULL;\r
+ gResetRequired = FALSE;\r
+ } else {\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ //\r
+ // Still show current page.\r
+ //\r
+ Selection->Action = UI_ACTION_NONE;\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ break;\r
+ }\r
+ }\r
\r
- Repaint = TRUE;\r
- NewLine = TRUE;\r
+ //\r
+ // Reterieve default setting. After it. NV flag will be showed.\r
+ //\r
+ if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+ Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
+ if (!EFI_ERROR (Status)) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ Selection->Statement = NULL;\r
+ gResetRequired = TRUE;\r
+ } else {\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ //\r
+ // Still show current page.\r
+ //\r
+ Selection->Action = UI_ACTION_NONE;\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ break;\r
+ }\r
}\r
- break;\r
\r
- case CfUiDefault:\r
- ControlFlag = CfCheckSelection;\r
- if (!Selection->FormEditable) {\r
+ //\r
+ // Save changes. After it, no NV flag is showed.\r
+ //\r
+ if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+ Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+ if (!EFI_ERROR (Status)) {\r
+ ASSERT(MenuOption != NULL);\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, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ //\r
+ // Still show current page.\r
+ //\r
+ Selection->Action = UI_ACTION_NONE;\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Set Reset required Flag\r
+ //\r
+ if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+ gResetRequired = TRUE;\r
+ }\r
+ \r
+ //\r
+ // Exit Action\r
+ //\r
+ if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
//\r
- // This Form is not editable, ignore the F9 (reset to default)\r
+ // Form Exit without saving, Similar to ESC Key.\r
+ // FormSet Exit without saving, Exit SendForm.\r
+ // System Exit without saving, CallExitHandler and Exit SendForm.\r
//\r
- break;\r
+ DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+ if (gBrowserSettingScope == FormLevel) {\r
+ ControlFlag = CfUiReset;\r
+ } else if (gBrowserSettingScope == FormSetLevel) {\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ } else if (gBrowserSettingScope == SystemLevel) {\r
+ if (ExitHandlerFunction != NULL) {\r
+ ExitHandlerFunction ();\r
+ }\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ }\r
+ Selection->Statement = NULL;\r
}\r
+ break;\r
\r
- Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
+ case CfUiDefault:\r
+ ControlFlag = CfCheckSelection;\r
+ //\r
+ // Reset to default value for all forms in the whole system.\r
+ //\r
+ Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);\r
\r
if (!EFI_ERROR (Status)) {\r
Selection->Action = UI_ACTION_REFRESH_FORM;\r
Selection->Statement = NULL;\r
-\r
- //\r
- // Show NV update flag on status bar\r
- //\r
- gNvUpdateRequired = TRUE;\r
+ gResetRequired = TRUE;\r
}\r
break;\r
\r
gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
gST->ConOut->OutputString (gST->ConOut, L"\n");\r
+ if (HelpString != NULL) {\r
+ FreePool (HelpString);\r
+ }\r
+ if (HelpHeaderString != NULL) {\r
+ FreePool (HelpHeaderString);\r
+ }\r
+ if (HelpBottomString != NULL) {\r
+ FreePool (HelpBottomString);\r
+ }\r
\r
return EFI_SUCCESS;\r
\r