-/** @file
-
-Copyright (c) 2004 - 2007, Intel Corporation
-All rights reserved. This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
- Ui.c
-
-Abstract:
-
- Implementation for UI.
-
-Revision History
-
-
-**/
-
-#include "Ui.h"
-#include "Setup.h"
-
-LIST_ENTRY Menu;
-LIST_ENTRY gMenuList;
-MENU_REFRESH_ENTRY *gMenuRefreshHead;
-
-//
-// Search table for UiDisplayMenu()
-//
-SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
- SCAN_UP,
- UiUp,
- SCAN_DOWN,
- UiDown,
- SCAN_PAGE_UP,
- UiPageUp,
- SCAN_PAGE_DOWN,
- UiPageDown,
- SCAN_ESC,
- UiReset,
- SCAN_F2,
- UiPrevious,
- SCAN_LEFT,
- UiLeft,
- SCAN_RIGHT,
- UiRight,
- SCAN_F9,
- UiDefault,
- SCAN_F10,
- UiSave
-};
-
-SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
- UiNoOperation,
- CfUiNoOperation,
- UiDefault,
- CfUiDefault,
- UiSelect,
- CfUiSelect,
- UiUp,
- CfUiUp,
- UiDown,
- CfUiDown,
- UiLeft,
- CfUiLeft,
- UiRight,
- CfUiRight,
- UiReset,
- CfUiReset,
- UiSave,
- CfUiSave,
- UiPrevious,
- CfUiPrevious,
- UiPageUp,
- CfUiPageUp,
- UiPageDown,
- CfUiPageDown
-};
-
-
-/**
- Set Buffer to Value for Size bytes.
-
- @param Buffer Memory to set.
- @param Size Number of bytes to set
- @param Value Value of the set operation.
-
- @return None
-
-**/
-VOID
-SetUnicodeMem (
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR16 Value
- )
-{
- CHAR16 *Ptr;
-
- Ptr = Buffer;
- while (Size--) {
- *(Ptr++) = Value;
- }
-}
-
-
-/**
- Initialize Menu option list.
-
- None.
-
- @return None.
-
-**/
-VOID
-UiInitMenu (
- VOID
- )
-{
- InitializeListHead (&Menu);
-}
-
-
-/**
- Initialize Menu option list.
-
- None.
-
- @return None.
-
-**/
-VOID
-UiInitMenuList (
- VOID
- )
-{
- InitializeListHead (&gMenuList);
-}
-
-
-/**
- Remove a Menu in list, and return FormId/QuestionId for previous Menu.
-
- @param Selection Menu selection.
-
- @return None.
-
-**/
-VOID
-UiRemoveMenuListEntry (
- IN OUT UI_MENU_SELECTION *Selection
- )
-{
- UI_MENU_LIST *UiMenuList;
-
- if (!IsListEmpty (&gMenuList)) {
- UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
-
- Selection->FormId = UiMenuList->FormId;
- Selection->QuestionId = UiMenuList->QuestionId;
- RemoveEntryList (&UiMenuList->MenuLink);
- gBS->FreePool (UiMenuList);
- }
-}
-
-
-/**
- Free Menu option linked list.
-
- None.
-
- @return None.
-
-**/
-VOID
-UiFreeMenuList (
- VOID
- )
-{
- UI_MENU_LIST *UiMenuList;
-
- while (!IsListEmpty (&gMenuList)) {
- UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
- RemoveEntryList (&UiMenuList->MenuLink);
- gBS->FreePool (UiMenuList);
- }
-}
-
-
-/**
- Add one menu entry to the linked lst
-
- @param Selection Menu selection.
-
- @return None.
-
-**/
-VOID
-UiAddMenuListEntry (
- IN UI_MENU_SELECTION *Selection
- )
-{
- UI_MENU_LIST *UiMenuList;
-
- UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));
- ASSERT (UiMenuList != NULL);
-
- UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;
- UiMenuList->FormId = Selection->FormId;
- UiMenuList->QuestionId = Selection->QuestionId;
-
- InsertHeadList (&gMenuList, &UiMenuList->MenuLink);
-}
-
-
-/**
- Free Menu option linked list.
-
- None.
-
- @return None.
-
-**/
-VOID
-UiFreeMenu (
- VOID
- )
-{
- UI_MENU_OPTION *MenuOption;
-
- while (!IsListEmpty (&Menu)) {
- MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);
- RemoveEntryList (&MenuOption->Link);
-
- //
- // We allocated space for this description when we did a GetToken, free it here
- //
- if (MenuOption->Skip != 0) {
- //
- // For date/time, MenuOption->Description is shared by three Menu Options
- // Data format : [01/02/2004] [11:22:33]
- // Line number : 0 0 1 0 0 1
- //
- gBS->FreePool (MenuOption->Description);
- }
- gBS->FreePool (MenuOption);
- }
-}
-
-
-/**
- Free Menu option linked list.
-
- None.
-
- @return None.
-
-**/
-VOID
-UiFreeRefreshList (
- VOID
- )
-{
- MENU_REFRESH_ENTRY *OldMenuRefreshEntry;
-
- while (gMenuRefreshHead != NULL) {
- OldMenuRefreshEntry = gMenuRefreshHead->Next;
- gBS->FreePool (gMenuRefreshHead);
- gMenuRefreshHead = OldMenuRefreshEntry;
- }
-
- gMenuRefreshHead = NULL;
-}
-
-
-
-/**
- Refresh screen.
-
- None.
-
- @return None.
-
-**/
-VOID
-RefreshForm (
- VOID
- )
-{
- CHAR16 *OptionString;
- MENU_REFRESH_ENTRY *MenuRefreshEntry;
- UINTN Index;
- UINTN Loop;
- EFI_STATUS Status;
- UI_MENU_SELECTION *Selection;
- FORM_BROWSER_STATEMENT *Question;
-
- OptionString = NULL;
-
- if (gMenuRefreshHead != NULL) {
-
- MenuRefreshEntry = gMenuRefreshHead;
-
- do {
- gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);
-
- Selection = MenuRefreshEntry->Selection;
- Question = MenuRefreshEntry->MenuOption->ThisTag;
-
- //
- // Don't update Question being edited
- //
- if (Question != MenuRefreshEntry->Selection->Statement) {
-
- Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);
-
- if (OptionString != NULL) {
- //
- // If leading spaces on OptionString - remove the spaces
- //
- for (Index = 0; OptionString[Index] == L' '; Index++)
- ;
-
- for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {
- OptionString[Loop] = OptionString[Index];
- Loop++;
- }
-
- OptionString[Loop] = CHAR_NULL;
-
- PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);
- gBS->FreePool (OptionString);
- }
- }
-
- MenuRefreshEntry = MenuRefreshEntry->Next;
-
- } while (MenuRefreshEntry != NULL);
- }
-}
-
-
-/**
- Wait for a given event to fire, or for an optional timeout to expire.
-
- @param Event The event to wait for
- @param Timeout An optional timeout value in 100 ns units.
- @param RefreshInterval Menu refresh interval (in seconds).
-
- @retval EFI_SUCCESS Event fired before Timeout expired.
- @retval EFI_TIME_OUT Timout expired before Event fired.
-
-**/
-EFI_STATUS
-UiWaitForSingleEvent (
- IN EFI_EVENT Event,
- IN UINT64 Timeout, OPTIONAL
- IN UINT8 RefreshInterval OPTIONAL
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- EFI_EVENT TimerEvent;
- EFI_EVENT WaitList[2];
-
- if (Timeout) {
- //
- // Create a timer event
- //
- Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
- if (!EFI_ERROR (Status)) {
- //
- // Set the timer event
- //
- gBS->SetTimer (
- TimerEvent,
- TimerRelative,
- Timeout
- );
-
- //
- // Wait for the original event or the timer
- //
- WaitList[0] = Event;
- WaitList[1] = TimerEvent;
- Status = gBS->WaitForEvent (2, WaitList, &Index);
- gBS->CloseEvent (TimerEvent);
-
- //
- // If the timer expired, change the return to timed out
- //
- if (!EFI_ERROR (Status) && Index == 1) {
- Status = EFI_TIMEOUT;
- }
- }
- } else {
- //
- // Update screen every second
- //
- if (RefreshInterval == 0) {
- Timeout = ONE_SECOND;
- } else {
- Timeout = RefreshInterval * ONE_SECOND;
- }
-
- do {
- Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
-
- //
- // Set the timer event
- //
- gBS->SetTimer (
- TimerEvent,
- TimerRelative,
- Timeout
- );
-
- //
- // Wait for the original event or the timer
- //
- WaitList[0] = Event;
- WaitList[1] = TimerEvent;
- Status = gBS->WaitForEvent (2, WaitList, &Index);
-
- //
- // If the timer expired, update anything that needs a refresh and keep waiting
- //
- if (!EFI_ERROR (Status) && Index == 1) {
- Status = EFI_TIMEOUT;
- if (RefreshInterval != 0) {
- RefreshForm ();
- }
- }
-
- gBS->CloseEvent (TimerEvent);
- } while (Status == EFI_TIMEOUT);
- }
-
- return Status;
-}
-
-
-/**
- Add one menu option by specified description and context.
-
- @param String String description for this option.
- @param Handle Hii handle for the package list.
- @param Statement Statement of this Menu Option.
- @param NumberOfLines Display lines for this Menu Option.
- @param MenuItemCount The index for this Option in the Menu.
-
- @return None.
-
-**/
-VOID
-UiAddMenuOption (
- IN CHAR16 *String,
- IN EFI_HII_HANDLE Handle,
- IN FORM_BROWSER_STATEMENT *Statement,
- IN UINT16 NumberOfLines,
- IN UINT16 MenuItemCount
- )
-{
- UI_MENU_OPTION *MenuOption;
- UINTN Index;
- UINTN Count;
-
- Count = 1;
-
- if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
- //
- // Add three MenuOptions for Date/Time
- // Data format : [01/02/2004] [11:22:33]
- // Line number : 0 0 1 0 0 1
- //
- NumberOfLines = 0;
- Count = 3;
-
- if (Statement->Storage == NULL) {
- //
- // For RTC type of date/time, set default refresh interval to be 1 second
- //
- if (Statement->RefreshInterval == 0) {
- Statement->RefreshInterval = 1;
- }
- }
- }
-
- for (Index = 0; Index < Count; Index++) {
- MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
- ASSERT (MenuOption);
-
- MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
- MenuOption->Description = String;
- MenuOption->Handle = Handle;
- MenuOption->ThisTag = Statement;
- MenuOption->EntryNumber = MenuItemCount;
-
- if (Index == 2) {
- //
- // Override LineNumber for the MenuOption in Date/Time sequence
- //
- MenuOption->Skip = 1;
- } else {
- MenuOption->Skip = NumberOfLines;
- }
- MenuOption->Sequence = Index;
-
- if (Statement->GrayOutExpression != NULL) {
- MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;
- }
-
- if ((Statement->ValueExpression != NULL) ||
- (Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY)) {
- MenuOption->ReadOnly = TRUE;
- }
-
- InsertTailList (&Menu, &MenuOption->Link);
- }
-}
-
-
-/**
- Routine used to abstract a generic dialog interface and return the selected key or string
-
- @param NumberOfLines The number of lines for the dialog box
- @param HotKey Defines whether a single character is parsed
- (TRUE) and returned in KeyValue or a string is
- returned in StringBuffer. Two special characters
- are considered when entering a string, a SCAN_ESC
- and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
- string input and returns
- @param MaximumStringSize The maximum size in bytes of a typed in string
- (each character is a CHAR16) and the minimum
- string returned is two bytes
- @param StringBuffer The passed in pointer to the buffer which will
- hold the typed in string if HotKey is FALSE
- @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
- @param String Pointer to the first string in the list
- @param ... A series of (quantity == NumberOfLines) text
- strings which will be used to construct the dialog
- box
-
- @retval EFI_SUCCESS Displayed dialog and received user interaction
- @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
- (StringBuffer == NULL) && (HotKey == FALSE))
- @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
-
-**/
-EFI_STATUS
-CreateDialog (
- IN UINTN NumberOfLines,
- IN BOOLEAN HotKey,
- IN UINTN MaximumStringSize,
- OUT CHAR16 *StringBuffer,
- OUT EFI_INPUT_KEY *KeyValue,
- IN CHAR16 *String,
- ...
- )
-{
- VA_LIST Marker;
- UINTN Count;
- EFI_INPUT_KEY Key;
- UINTN LargestString;
- CHAR16 *TempString;
- CHAR16 *BufferedString;
- CHAR16 *StackString;
- CHAR16 KeyPad[2];
- UINTN Start;
- UINTN Top;
- UINTN Index;
- EFI_STATUS Status;
- BOOLEAN SelectionComplete;
- UINTN InputOffset;
- UINTN CurrentAttribute;
- UINTN DimensionsWidth;
- UINTN DimensionsHeight;
-
- DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
- DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
-
- SelectionComplete = FALSE;
- InputOffset = 0;
- TempString = AllocateZeroPool (MaximumStringSize * 2);
- BufferedString = AllocateZeroPool (MaximumStringSize * 2);
- CurrentAttribute = gST->ConOut->Mode->Attribute;
-
- ASSERT (TempString);
- ASSERT (BufferedString);
-
- VA_START (Marker, String);
-
- //
- // Zero the outgoing buffer
- //
- ZeroMem (StringBuffer, MaximumStringSize);
-
- if (HotKey) {
- if (KeyValue == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- } else {
- if (StringBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- }
- //
- // Disable cursor
- //
- gST->ConOut->EnableCursor (gST->ConOut, FALSE);
-
- LargestString = (GetStringWidth (String) / 2);
-
- if (*String == L' ') {
- InputOffset = 1;
- }
- //
- // Determine the largest string in the dialog box
- // Notice we are starting with 1 since String is the first string
- //
- for (Count = 1; Count < NumberOfLines; Count++) {
- StackString = VA_ARG (Marker, CHAR16 *);
-
- if (StackString[0] == L' ') {
- InputOffset = Count + 1;
- }
-
- if ((GetStringWidth (StackString) / 2) > LargestString) {
- //
- // Size of the string visually and subtract the width by one for the null-terminator
- //
- LargestString = (GetStringWidth (StackString) / 2);
- }
- }
-
- Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;
- Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
-
- Count = 0;
-
- //
- // Display the Popup
- //
- CreateSharedPopUp (LargestString, NumberOfLines, &String);
-
- //
- // Take the first key typed and report it back?
- //
- if (HotKey) {
- Status = WaitForKeyStroke (&Key);
- ASSERT_EFI_ERROR (Status);
- CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
-
- } else {
- do {
- Status = WaitForKeyStroke (&Key);
-
- switch (Key.UnicodeChar) {
- case CHAR_NULL:
- switch (Key.ScanCode) {
- case SCAN_ESC:
- gBS->FreePool (TempString);
- gBS->FreePool (BufferedString);
- gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
- return EFI_DEVICE_ERROR;
-
- default:
- break;
- }
-
- break;
-
- case CHAR_CARRIAGE_RETURN:
- SelectionComplete = TRUE;
- gBS->FreePool (TempString);
- gBS->FreePool (BufferedString);
- gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
- return EFI_SUCCESS;
- break;
-
- case CHAR_BACKSPACE:
- if (StringBuffer[0] != CHAR_NULL) {
- for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {
- TempString[Index] = StringBuffer[Index];
- }
- //
- // Effectively truncate string by 1 character
- //
- TempString[Index - 1] = CHAR_NULL;
- StrCpy (StringBuffer, TempString);
- }
-
- default:
- //
- // If it is the beginning of the string, don't worry about checking maximum limits
- //
- if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
- StrnCpy (StringBuffer, &Key.UnicodeChar, 1);
- StrnCpy (TempString, &Key.UnicodeChar, 1);
- } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
- KeyPad[0] = Key.UnicodeChar;
- KeyPad[1] = CHAR_NULL;
- StrCat (StringBuffer, KeyPad);
- StrCat (TempString, KeyPad);
- }
- //
- // If the width of the input string is now larger than the screen, we nee to
- // adjust the index to start printing portions of the string
- //
- SetUnicodeMem (BufferedString, LargestString, L' ');
-
- PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
-
- if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {
- Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;
- } else {
- Index = 0;
- }
-
- for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {
- BufferedString[Count] = StringBuffer[Index];
- }
-
- PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
- break;
- }
- } while (!SelectionComplete);
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
- return EFI_SUCCESS;
-}
-
-VOID
-CreateSharedPopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- IN CHAR16 **ArrayOfStrings
- )
-{
- UINTN Index;
- UINTN Count;
- CHAR16 Character;
- UINTN Start;
- UINTN End;
- UINTN Top;
- UINTN Bottom;
- CHAR16 *String;
- UINTN DimensionsWidth;
- UINTN DimensionsHeight;
-
- DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
- DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
-
- Count = 0;
-
- gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
-
- if ((RequestedWidth + 2) > DimensionsWidth) {
- RequestedWidth = DimensionsWidth - 2;
- }
-
- //
- // Subtract the PopUp width from total Columns, allow for one space extra on
- // each end plus a border.
- //
- Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;
- End = Start + RequestedWidth + 1;
-
- Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
- Bottom = Top + NumberOfLines + 2;
-
- Character = BOXDRAW_DOWN_RIGHT;
- PrintCharAt (Start, Top, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = Start; Index + 2 < End; Index++) {
- PrintChar (Character);
- }
-
- Character = BOXDRAW_DOWN_LEFT;
- PrintChar (Character);
- Character = BOXDRAW_VERTICAL;
- for (Index = Top; Index + 2 < Bottom; Index++) {
- String = ArrayOfStrings[Count];
- Count++;
-
- //
- // This will clear the background of the line - we never know who might have been
- // here before us. This differs from the next clear in that it used the non-reverse
- // video for normal printing.
- //
- if (GetStringWidth (String) / 2 > 1) {
- ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
- }
-
- //
- // Passing in a space results in the assumption that this is where typing will occur
- //
- if (String[0] == L' ') {
- ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);
- }
-
- //
- // Passing in a NULL results in a blank space
- //
- if (String[0] == CHAR_NULL) {
- ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
- }
-
- PrintStringAt (
- ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
- Index + 1,
- String
- );
- gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
- PrintCharAt (Start, Index + 1, Character);
- PrintCharAt (End - 1, Index + 1, Character);
- }
-
- Character = BOXDRAW_UP_RIGHT;
- PrintCharAt (Start, Bottom - 1, Character);
- Character = BOXDRAW_HORIZONTAL;
- for (Index = Start; Index + 2 < End; Index++) {
- PrintChar (Character);
- }
-
- Character = BOXDRAW_UP_LEFT;
- PrintChar (Character);
-}
-
-VOID
-CreatePopUp (
- IN UINTN RequestedWidth,
- IN UINTN NumberOfLines,
- IN CHAR16 *ArrayOfStrings,
- ...
- )
-{
- CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);
-}
-
-
-/**
- Update status bar on the bottom of menu.
-
- @param MessageType The type of message to be shown.
- @param Flags The flags in Question header.
- @param State Set or clear.
-
- @return None.
-
-**/
-VOID
-UpdateStatusBar (
- IN UINTN MessageType,
- IN UINT8 Flags,
- IN BOOLEAN State
- )
-{
- UINTN Index;
- STATIC BOOLEAN InputError;
- CHAR16 *NvUpdateMessage;
- CHAR16 *InputErrorMessage;
-
- NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);
- InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);
-
- switch (MessageType) {
- case INPUT_ERROR:
- if (State) {
- gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);
- PrintStringAt (
- gScreenDimensions.LeftColumn + gPromptBlockWidth,
- gScreenDimensions.BottomRow - 1,
- InputErrorMessage
- );
- InputError = TRUE;
- } else {
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
- for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {
- PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");
- }
-
- InputError = FALSE;
- }
- break;
-
- case NV_UPDATE_REQUIRED:
- if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
- if (State) {
- gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);
- PrintStringAt (
- gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,
- gScreenDimensions.BottomRow - 1,
- NvUpdateMessage
- );
- gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));
-
- gNvUpdateRequired = TRUE;
- } else {
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
- for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {
- PrintAt (
- (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),
- gScreenDimensions.BottomRow - 1,
- L" "
- );
- }
-
- gNvUpdateRequired = FALSE;
- }
- }
- break;
-
- case REFRESH_STATUS_BAR:
- if (InputError) {
- UpdateStatusBar (INPUT_ERROR, Flags, TRUE);
- }
-
- if (gNvUpdateRequired) {
- UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);
- }
- break;
-
- default:
- break;
- }
-
- gBS->FreePool (InputErrorMessage);
- gBS->FreePool (NvUpdateMessage);
- return ;
-}
-
-
-/**
- Get the supported width for a particular op-code
-
- @param Statement The FORM_BROWSER_STATEMENT structure passed in.
- @param Handle The handle in the HII database being used
-
- @return Returns the number of CHAR16 characters that is support.
-
-**/
-UINT16
-GetWidth (
- IN FORM_BROWSER_STATEMENT *Statement,
- IN EFI_HII_HANDLE Handle
- )
-{
- CHAR16 *String;
- UINTN Size;
- UINT16 Width;
-
- Size = 0;
-
- //
- // See if the second text parameter is really NULL
- //
- if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {
- String = GetToken (Statement->TextTwo, Handle);
- Size = StrLen (String);
- gBS->FreePool (String);
- }
-
- if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||
- (Statement->Operand == EFI_IFR_REF_OP) ||
- (Statement->Operand == EFI_IFR_PASSWORD_OP) ||
- (Statement->Operand == EFI_IFR_ACTION_OP) ||
- (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||
- //
- // Allow a wide display if text op-code and no secondary text op-code
- //
- ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))
- ) {
- Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);
- } else {
- Width = (UINT16) gPromptBlockWidth;
- }
-
- if (Statement->InSubtitle) {
- Width -= SUBTITLE_INDENT;
- }
-
- return Width;
-}
-
-
-/**
- Will copy LineWidth amount of a string in the OutputString buffer and return the
- number of CHAR16 characters that were copied into the OutputString buffer.
-
- @param InputString String description for this option.
- @param LineWidth Width of the desired string to extract in CHAR16
- characters
- @param Index Where in InputString to start the copy process
- @param OutputString Buffer to copy the string into
-
- @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
-
-**/
-UINT16
-GetLineByWidth (
- IN CHAR16 *InputString,
- IN UINT16 LineWidth,
- IN OUT UINTN *Index,
- OUT CHAR16 **OutputString
- )
-{
- static BOOLEAN Finished;
- UINT16 Count;
- UINT16 Count2;
-
- if (Finished) {
- Finished = FALSE;
- return (UINT16) 0;
- }
-
- Count = LineWidth;
- Count2 = 0;
-
- *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));
-
- //
- // Ensure we have got a valid buffer
- //
- if (*OutputString != NULL) {
-
- //
- //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.
- //To avoid displaying this empty line in screen, just skip the two CHARs here.
- //
- if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
- *Index = *Index + 2;
- }
-
- //
- // Fast-forward the string and see if there is a carriage-return in the string
- //
- for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)
- ;
-
- //
- // Copy the desired LineWidth of data to the output buffer.
- // Also make sure that we don't copy more than the string.
- // Also make sure that if there are linefeeds, we account for them.
- //
- if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&
- (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))
- ) {
- //
- // Convert to CHAR16 value and show that we are done with this operation
- //
- LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);
- if (LineWidth != 0) {
- Finished = TRUE;
- }
- } else {
- if (Count2 == LineWidth) {
- //
- // Rewind the string from the maximum size until we see a space to break the line
- //
- for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)
- ;
- if (LineWidth == 0) {
- LineWidth = Count;
- }
- } else {
- LineWidth = Count2;
- }
- }
-
- CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);
-
- //
- // If currently pointing to a space, increment the index to the first non-space character
- //
- for (;
- (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);
- (*Index)++
- )
- ;
- *Index = (UINT16) (*Index + LineWidth);
- return LineWidth;
- } else {
- return (UINT16) 0;
- }
-}
-
-
-/**
- Update display lines for a Menu Option.
-
- @param MenuOption The MenuOption to be checked.
-
- @retval TRUE This Menu Option is selectable.
- @retval FALSE This Menu Option could not be selected.
-
-**/
-VOID
-UpdateOptionSkipLines (
- IN UI_MENU_SELECTION *Selection,
- IN UI_MENU_OPTION *MenuOption,
- IN CHAR16 **OptionalString,
- IN UINTN SkipValue
- )
-{
- UINTN Index;
- UINT16 Width;
- UINTN Row;
- UINTN OriginalRow;
- CHAR16 *OutputString;
- CHAR16 *OptionString;
-
- Row = 0;
- OptionString = *OptionalString;
- OutputString = NULL;
-
- ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-
- if (OptionString != NULL) {
- Width = (UINT16) gOptionBlockWidth;
-
- OriginalRow = Row;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&OptionString[Index])) {
- if (SkipValue == 0) {
- Row++;
- //
- // Since the Number of lines for this menu entry may or may not be reflected accurately
- // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
- // some testing to ensure we are keeping this in-sync.
- //
- // If the difference in rows is greater than or equal to the skip value, increase the skip value
- //
- if ((Row - OriginalRow) >= MenuOption->Skip) {
- MenuOption->Skip++;
- }
- }
- }
-
- gBS->FreePool (OutputString);
- if (SkipValue != 0) {
- SkipValue--;
- }
- }
-
- Row = OriginalRow;
- }
-
- *OptionalString = OptionString;
-}
-
-
-/**
- Check whether this Menu Option could be highlighted.
-
- @param MenuOption The MenuOption to be checked.
-
- @retval TRUE This Menu Option is selectable.
- @retval FALSE This Menu Option could not be selected.
-
-**/
-STATIC
-BOOLEAN
-IsSelectable (
- UI_MENU_OPTION *MenuOption
- )
-{
- if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||
- MenuOption->GrayOut || MenuOption->ReadOnly) {
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-
-/**
- Determine if the menu is the last menu that can be selected.
-
- @param Direction the scroll direction. False is down. True is up.
-
- @return FALSE -- the menu isn't the last menu that can be selected.
- @return TRUE -- the menu is the last menu that can be selected.
-
-**/
-STATIC
-BOOLEAN
-ValueIsScroll (
- IN BOOLEAN Direction,
- IN LIST_ENTRY *CurrentPos
- )
-{
- LIST_ENTRY *Temp;
- UI_MENU_OPTION *MenuOption;
-
- Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
-
- if (Temp == &Menu) {
- return TRUE;
- }
-
- for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {
- MenuOption = MENU_OPTION_FROM_LINK (Temp);
- if (IsSelectable (MenuOption)) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-
-/**
- Move to next selectable statement.
-
- @param GoUp The navigation direction. TRUE: up, FALSE: down.
- @param CurrentPosition Current position.
-
- @return The row distance from current MenuOption to next selectable MenuOption.
-
-**/
-STATIC
-INTN
-MoveToNextStatement (
- IN BOOLEAN GoUp,
- IN OUT LIST_ENTRY **CurrentPosition
- )
-{
- INTN Distance;
- LIST_ENTRY *Pos;
- BOOLEAN HitEnd;
- UI_MENU_OPTION *NextMenuOption;
-
- Distance = 0;
- Pos = *CurrentPosition;
- HitEnd = FALSE;
-
- while (TRUE) {
- NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
- if (IsSelectable (NextMenuOption)) {
- break;
- }
- if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {
- HitEnd = TRUE;
- break;
- }
- Distance += NextMenuOption->Skip;
- Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
- }
-
- if (HitEnd) {
- //
- // If we hit end there is still no statement can be focused,
- // we go backwards to find the statement can be focused.
- //
- Distance = 0;
- Pos = *CurrentPosition;
-
- while (TRUE) {
- NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
- if (IsSelectable (NextMenuOption)) {
- break;
- }
- if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {
- ASSERT (FALSE);
- break;
- }
- Distance -= NextMenuOption->Skip;
- Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);
- }
- }
-
- *CurrentPosition = &NextMenuOption->Link;
- return Distance;
-}
-
-
-/**
- Adjust Data and Time position accordingly.
- Data format : [01/02/2004] [11:22:33]
- Line number : 0 0 1 0 0 1
-
- @param DirectionUp the up or down direction. False is down. True is
- up.
- @param CurrentPosition Current position. On return: Point to the last
- Option (Year or Second) if up; Point to the first
- Option (Month or Hour) if down.
-
- @return Return line number to pad. It is possible that we stand on a zero-advance
- @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
-
-**/
-STATIC
-UINTN
-AdjustDateAndTimePosition (
- IN BOOLEAN DirectionUp,
- IN OUT LIST_ENTRY **CurrentPosition
- )
-{
- UINTN Count;
- LIST_ENTRY *NewPosition;
- UI_MENU_OPTION *MenuOption;
- UINTN PadLineNumber;
-
- PadLineNumber = 0;
- NewPosition = *CurrentPosition;
- MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
-
- if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
- (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
- //
- // Calculate the distance from current position to the last Date/Time MenuOption
- //
- Count = 0;
- while (MenuOption->Skip == 0) {
- Count++;
- NewPosition = NewPosition->ForwardLink;
- MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
- PadLineNumber = 1;
- }
-
- NewPosition = *CurrentPosition;
- if (DirectionUp) {
- //
- // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
- // to be one that back to the previous set of MenuOptions, we need to advance to the first
- // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
- // checking can be done.
- //
- while (Count++ < 2) {
- NewPosition = NewPosition->BackLink;
- }
- } else {
- //
- // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
- // to be one that progresses to the next set of MenuOptions, we need to advance to the last
- // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
- // checking can be done.
- //
- while (Count-- > 0) {
- NewPosition = NewPosition->ForwardLink;
- }
- }
-
- *CurrentPosition = NewPosition;
- }
-
- return PadLineNumber;
-}
-
-
-/**
- Display menu and wait for user to select one menu option, then return it.
- If AutoBoot is enabled, then if user doesn't select any option,
- after period of time, it will automatically return the first menu option.
-
-
- @return Return the pointer of the menu which selected,
- @return otherwise return NULL.
-
-**/
-EFI_STATUS
-UiDisplayMenu (
- IN OUT UI_MENU_SELECTION *Selection
- )
-{
- INTN SkipValue;
- INTN Difference;
- INTN OldSkipValue;
- UINTN DistanceValue;
- UINTN Row;
- UINTN Col;
- UINTN Temp;
- UINTN Temp2;
- UINTN TopRow;
- UINTN BottomRow;
- UINTN OriginalRow;
- UINTN Index;
- UINT32 Count;
- UINT16 Width;
- CHAR16 *StringPtr;
- CHAR16 *OptionString;
- CHAR16 *OutputString;
- CHAR16 *FormattedString;
- CHAR16 YesResponse;
- CHAR16 NoResponse;
- BOOLEAN NewLine;
- BOOLEAN Repaint;
- BOOLEAN SavedValue;
- EFI_STATUS Status;
- EFI_INPUT_KEY Key;
- LIST_ENTRY *Link;
- LIST_ENTRY *NewPos;
- LIST_ENTRY *TopOfScreen;
- LIST_ENTRY *SavedListEntry;
- UI_MENU_OPTION *MenuOption;
- UI_MENU_OPTION *NextMenuOption;
- UI_MENU_OPTION *SavedMenuOption;
- UI_MENU_OPTION *PreviousMenuOption;
- UI_CONTROL_FLAG ControlFlag;
- EFI_SCREEN_DESCRIPTOR LocalScreen;
- MENU_REFRESH_ENTRY *MenuRefreshEntry;
- UI_SCREEN_OPERATION ScreenOperation;
- UINT8 MinRefreshInterval;
- UINTN BufferSize;
- UINT16 DefaultId;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- FORM_BROWSER_STATEMENT *Statement;
-
- CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
-
- Status = EFI_SUCCESS;
- FormattedString = NULL;
- OptionString = NULL;
- ScreenOperation = UiNoOperation;
- NewLine = TRUE;
- MinRefreshInterval = 0;
- DefaultId = 0;
-
- OutputString = NULL;
- gUpArrow = FALSE;
- gDownArrow = FALSE;
- SkipValue = 0;
- OldSkipValue = 0;
- MenuRefreshEntry = gMenuRefreshHead;
-
- NextMenuOption = NULL;
- PreviousMenuOption = NULL;
- SavedMenuOption = NULL;
-
- ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
-
- if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
- TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
- Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
- } else {
- TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
- Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
- }
-
- Col = LocalScreen.LeftColumn;
- BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;
-
- Selection->TopRow = TopRow;
- Selection->BottomRow = BottomRow;
- Selection->PromptCol = Col;
- Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
- Selection->Statement = NULL;
-
- TopOfScreen = Menu.ForwardLink;
- Repaint = TRUE;
- MenuOption = NULL;
-
- //
- // Get user's selection
- //
- NewPos = Menu.ForwardLink;
-
- gST->ConOut->EnableCursor (gST->ConOut, FALSE);
- UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);
-
- ControlFlag = CfInitialization;
- Selection->Action = UI_ACTION_NONE;
- while (TRUE) {
- switch (ControlFlag) {
- case CfInitialization:
- if (IsListEmpty (&Menu)) {
- ControlFlag = CfReadKey;
- } else {
- ControlFlag = CfCheckSelection;
- }
- break;
-
- case CfCheckSelection:
- if (Selection->Action != UI_ACTION_NONE) {
- ControlFlag = CfExit;
- } else {
- ControlFlag = CfRepaint;
- }
- break;
-
- case CfRepaint:
- ControlFlag = CfRefreshHighLight;
-
- if (Repaint) {
- //
- // Display menu
- //
- gDownArrow = FALSE;
- gUpArrow = FALSE;
- Row = TopRow;
-
- Temp = SkipValue;
- Temp2 = SkipValue;
-
- ClearLines (
- LocalScreen.LeftColumn,
- LocalScreen.RightColumn,
- TopRow - SCROLL_ARROW_HEIGHT,
- BottomRow + SCROLL_ARROW_HEIGHT,
- FIELD_TEXT | FIELD_BACKGROUND
- );
-
- UiFreeRefreshList ();
- MinRefreshInterval = 0;
-
- for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {
- MenuOption = MENU_OPTION_FROM_LINK (Link);
- MenuOption->Row = Row;
- MenuOption->Col = Col;
- MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
-
- Statement = MenuOption->ThisTag;
- if (Statement->InSubtitle) {
- MenuOption->Col += SUBTITLE_INDENT;
- }
-
- if (MenuOption->GrayOut) {
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
- } else {
- if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {
- gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
- }
- }
-
- Width = GetWidth (Statement, MenuOption->Handle);
- OriginalRow = Row;
-
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
- if ((Temp == 0) && (Row <= BottomRow)) {
- PrintStringAt (MenuOption->Col, Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&MenuOption->Description[Index])) {
- if (Temp == 0) {
- Row++;
- }
- }
-
- gBS->FreePool (OutputString);
- if (Temp != 0) {
- Temp--;
- }
- }
-
- Temp = 0;
- Row = OriginalRow;
-
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-
- if (OptionString != NULL) {
- if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
- //
- // If leading spaces on OptionString - remove the spaces
- //
- for (Index = 0; OptionString[Index] == L' '; Index++) {
- MenuOption->OptCol++;
- }
-
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
- OptionString[Count] = OptionString[Index];
- Count++;
- }
-
- OptionString[Count] = CHAR_NULL;
- }
-
- //
- // If Question request refresh, register the op-code
- //
- if (Statement->RefreshInterval != 0) {
- //
- // Menu will be refreshed at minimal interval of all Questions
- // which have refresh request
- //
- if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {
- MinRefreshInterval = Statement->RefreshInterval;
- }
-
- if (gMenuRefreshHead == NULL) {
- MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
- ASSERT (MenuRefreshEntry != NULL);
- MenuRefreshEntry->MenuOption = MenuOption;
- MenuRefreshEntry->Selection = Selection;
- MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;
- MenuRefreshEntry->CurrentRow = MenuOption->Row;
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
- gMenuRefreshHead = MenuRefreshEntry;
- } else {
- //
- // Advance to the last entry
- //
- for (MenuRefreshEntry = gMenuRefreshHead;
- MenuRefreshEntry->Next != NULL;
- MenuRefreshEntry = MenuRefreshEntry->Next
- )
- ;
- MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
- ASSERT (MenuRefreshEntry->Next != NULL);
- MenuRefreshEntry = MenuRefreshEntry->Next;
- MenuRefreshEntry->MenuOption = MenuOption;
- MenuRefreshEntry->Selection = Selection;
- MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;
- MenuRefreshEntry->CurrentRow = MenuOption->Row;
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
- }
- }
-
- Width = (UINT16) gOptionBlockWidth;
- OriginalRow = Row;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
- if ((Temp2 == 0) && (Row <= BottomRow)) {
- PrintStringAt (MenuOption->OptCol, Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&OptionString[Index])) {
- if (Temp2 == 0) {
- Row++;
- //
- // Since the Number of lines for this menu entry may or may not be reflected accurately
- // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
- // some testing to ensure we are keeping this in-sync.
- //
- // If the difference in rows is greater than or equal to the skip value, increase the skip value
- //
- if ((Row - OriginalRow) >= MenuOption->Skip) {
- MenuOption->Skip++;
- }
- }
- }
-
- gBS->FreePool (OutputString);
- if (Temp2 != 0) {
- Temp2--;
- }
- }
-
- Temp2 = 0;
- Row = OriginalRow;
-
- gBS->FreePool (OptionString);
- }
- //
- // If this is a text op with secondary text information
- //
- if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {
- StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);
-
- Width = (UINT16) gOptionBlockWidth;
- OriginalRow = Row;
-
- for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {
- if ((Temp == 0) && (Row <= BottomRow)) {
- PrintStringAt (MenuOption->OptCol, Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&StringPtr[Index])) {
- if (Temp2 == 0) {
- Row++;
- //
- // Since the Number of lines for this menu entry may or may not be reflected accurately
- // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
- // some testing to ensure we are keeping this in-sync.
- //
- // If the difference in rows is greater than or equal to the skip value, increase the skip value
- //
- if ((Row - OriginalRow) >= MenuOption->Skip) {
- MenuOption->Skip++;
- }
- }
- }
-
- gBS->FreePool (OutputString);
- if (Temp2 != 0) {
- Temp2--;
- }
- }
-
- Row = OriginalRow;
- gBS->FreePool (StringPtr);
- }
-
- //
- // Need to handle the bottom of the display
- //
- if (MenuOption->Skip > 1) {
- Row += MenuOption->Skip - SkipValue;
- SkipValue = 0;
- } else {
- Row += MenuOption->Skip;
- }
-
- if (Row > BottomRow) {
- if (!ValueIsScroll (FALSE, Link)) {
- gDownArrow = TRUE;
- }
-
- Row = BottomRow + 1;
- break;
- }
- }
-
- if (!ValueIsScroll (TRUE, TopOfScreen)) {
- gUpArrow = TRUE;
- }
-
- if (gUpArrow) {
- gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
- PrintAt (
- LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
- TopRow - SCROLL_ARROW_HEIGHT,
- L"%c",
- ARROW_UP
- );
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- }
-
- if (gDownArrow) {
- gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
- PrintAt (
- LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
- BottomRow + SCROLL_ARROW_HEIGHT,
- L"%c",
- ARROW_DOWN
- );
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- }
-
- MenuOption = NULL;
- }
- break;
-
- case CfRefreshHighLight:
- //
- // MenuOption: Last menu option that need to remove hilight
- // MenuOption is set to NULL in Repaint
- // NewPos: Current menu option that need to hilight
- //
- ControlFlag = CfUpdateHelpString;
-
- //
- // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
- // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
- //
- SavedValue = Repaint;
- Repaint = FALSE;
-
- if (Selection->QuestionId != 0) {
- NewPos = Menu.ForwardLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {
- NewPos = NewPos->ForwardLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
- }
- if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {
- //
- // Target Question found, find its MenuOption
- //
- Link = TopOfScreen;
-
- for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {
- SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index += SavedMenuOption->Skip;
- Link = Link->ForwardLink;
- }
-
- if (Link != NewPos || Index > BottomRow) {
- //
- // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
- //
- Link = NewPos;
- for (Index = TopRow; Index <= BottomRow; ) {
- Link = Link->BackLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index += SavedMenuOption->Skip;
- }
- TopOfScreen = Link->ForwardLink;
-
- Repaint = TRUE;
- NewLine = TRUE;
- ControlFlag = CfRepaint;
- break;
- }
- } else {
- //
- // Target Question not found, highlight the default menu option
- //
- NewPos = TopOfScreen;
- }
-
- Selection->QuestionId = 0;
- }
-
- if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {
- if (MenuOption != NULL) {
- //
- // Remove highlight on last Menu Option
- //
- gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
- ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- if (OptionString != NULL) {
- if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
- (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)
- ) {
- //
- // If leading spaces on OptionString - remove the spaces
- //
- for (Index = 0; OptionString[Index] == L' '; Index++)
- ;
-
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
- OptionString[Count] = OptionString[Index];
- Count++;
- }
-
- OptionString[Count] = CHAR_NULL;
- }
-
- Width = (UINT16) gOptionBlockWidth;
- OriginalRow = MenuOption->Row;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
- PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&OptionString[Index])) {
- MenuOption->Row++;
- }
-
- gBS->FreePool (OutputString);
- }
-
- MenuOption->Row = OriginalRow;
-
- gBS->FreePool (OptionString);
- } else {
- if (NewLine) {
- if (MenuOption->GrayOut) {
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
- } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {
- gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
- }
-
- OriginalRow = MenuOption->Row;
- Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
-
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
- PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&MenuOption->Description[Index])) {
- MenuOption->Row++;
- }
-
- gBS->FreePool (OutputString);
- }
-
- MenuOption->Row = OriginalRow;
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- }
- }
- }
-
- //
- // This is only possible if we entered this page and the first menu option is
- // a "non-menu" item. In that case, force it UiDown
- //
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- if (!IsSelectable (MenuOption)) {
- ASSERT (ScreenOperation == UiNoOperation);
- ScreenOperation = UiDown;
- ControlFlag = CfScreenOperation;
- break;
- }
-
- //
- // This is the current selected statement
- //
- Statement = MenuOption->ThisTag;
- Selection->Statement = Statement;
-
- //
- // Set reverse attribute
- //
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
- gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
-
- //
- // Assuming that we have a refresh linked-list created, lets annotate the
- // appropriate entry that we are highlighting with its new attribute. Just prior to this
- // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
- //
- if (gMenuRefreshHead != NULL) {
- for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
- if (MenuRefreshEntry->MenuOption == MenuOption) {
- MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;
- }
- }
- }
-
- ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
- if (OptionString != NULL) {
- if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
- //
- // If leading spaces on OptionString - remove the spaces
- //
- for (Index = 0; OptionString[Index] == L' '; Index++)
- ;
-
- for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
- OptionString[Count] = OptionString[Index];
- Count++;
- }
-
- OptionString[Count] = CHAR_NULL;
- }
- Width = (UINT16) gOptionBlockWidth;
-
- OriginalRow = MenuOption->Row;
-
- for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
- PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&OptionString[Index])) {
- MenuOption->Row++;
- }
-
- gBS->FreePool (OutputString);
- }
-
- MenuOption->Row = OriginalRow;
-
- gBS->FreePool (OptionString);
- } else {
- if (NewLine) {
- OriginalRow = MenuOption->Row;
-
- Width = GetWidth (Statement, MenuOption->Handle);
-
- for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
- if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
- PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
- }
- //
- // If there is more string to process print on the next row and increment the Skip value
- //
- if (StrLen (&MenuOption->Description[Index])) {
- MenuOption->Row++;
- }
-
- gBS->FreePool (OutputString);
- }
-
- MenuOption->Row = OriginalRow;
-
- }
- }
-
- if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||
- ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||
- (ScreenOperation == UiNoOperation)
- ) {
- UpdateKeyHelp (MenuOption, FALSE);
- }
- //
- // Clear reverse attribute
- //
- gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
- }
- //
- // Repaint flag will be used when process CfUpdateHelpString, so restore its value
- // if we didn't break halfway when process CfRefreshHighLight.
- //
- Repaint = SavedValue;
- break;
-
- case CfUpdateHelpString:
- ControlFlag = CfPrepareToReadKey;
-
- if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) {
- //
- // Don't print anything if it is a NULL help token
- //
- if (MenuOption->ThisTag->Help == 0) {
- StringPtr = L"\0";
- } else {
- StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);
- }
-
- ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);
-
- gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);
-
- for (Index = 0; Index < BottomRow - TopRow; Index++) {
- //
- // Pad String with spaces to simulate a clearing of the previous line
- //
- for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {
- StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");
- }
-
- PrintStringAt (
- LocalScreen.RightColumn - gHelpBlockWidth,
- Index + TopRow,
- &FormattedString[Index * gHelpBlockWidth * 2]
- );
- }
- }
- //
- // Reset this flag every time we finish using it.
- //
- Repaint = FALSE;
- NewLine = FALSE;
- break;
-
- case CfPrepareToReadKey:
- ControlFlag = CfReadKey;
- ScreenOperation = UiNoOperation;
- break;
-
- case CfReadKey:
- ControlFlag = CfScreenOperation;
-
- //
- // Wait for user's selection
- //
- do {
- Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);
- } while (Status == EFI_TIMEOUT);
-
- if (Status == EFI_TIMEOUT) {
- Key.UnicodeChar = CHAR_CARRIAGE_RETURN;
- } else {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- //
- // if we encounter error, continue to read another key in.
- //
- if (EFI_ERROR (Status)) {
- ControlFlag = CfReadKey;
- continue;
- }
- }
-
- if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {
- //
- // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
- //
- break;
- }
-
- switch (Key.UnicodeChar) {
- case CHAR_CARRIAGE_RETURN:
- ScreenOperation = UiSelect;
- gDirection = 0;
- break;
-
- //
- // We will push the adjustment of these numeric values directly to the input handler
- // NOTE: we won't handle manual input numeric
- //
- case '+':
- case '-':
- Statement = MenuOption->ThisTag;
- if ((Statement->Operand == EFI_IFR_DATE_OP)
- || (Statement->Operand == EFI_IFR_TIME_OP)
- || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))
- ){
- if (Key.UnicodeChar == '+') {
- gDirection = SCAN_RIGHT;
- } else {
- gDirection = SCAN_LEFT;
- }
- Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);
- SafeFreePool (OptionString);
- }
- break;
-
- case '^':
- ScreenOperation = UiUp;
- break;
-
- case 'V':
- case 'v':
- ScreenOperation = UiDown;
- break;
-
- case ' ':
- if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
- if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {
- ScreenOperation = UiSelect;
- }
- }
- break;
-
- case CHAR_NULL:
- if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||
- ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||
- ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||
- ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))
- ) {
- //
- // If the function key has been disabled, just ignore the key.
- //
- } else {
- for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {
- if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
- if (Key.ScanCode == SCAN_F9) {
- //
- // Reset to standard default
- //
- DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
- }
- ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
- break;
- }
- }
- }
- break;
- }
- break;
-
- case CfScreenOperation:
- if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {
- //
- // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
- // ignore the selection and go back to reading keys.
- //
- if (IsListEmpty (&Menu)) {
- ControlFlag = CfReadKey;
- break;
- }
- //
- // if there is nothing logical to place a cursor on, just move on to wait for a key.
- //
- for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {
- NextMenuOption = MENU_OPTION_FROM_LINK (Link);
- if (IsSelectable (NextMenuOption)) {
- break;
- }
- }
-
- if (Link == &Menu) {
- ControlFlag = CfPrepareToReadKey;
- break;
- }
- } else if (ScreenOperation == UiReset) {
- //
- // Press ESC to exit FormSet
- //
- Selection->Action = UI_ACTION_EXIT;
- Selection->Statement = NULL;
- }
-
- for (Index = 0;
- Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
- Index++
- ) {
- if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
- ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
- break;
- }
- }
- break;
-
- case CfUiPrevious:
- ControlFlag = CfCheckSelection;
-
- if (IsListEmpty (&gMenuList)) {
- Selection->Action = UI_ACTION_NONE;
- if (IsListEmpty (&Menu)) {
- ControlFlag = CfReadKey;
- }
- break;
- }
-
- //
- // Remove the Cached page entry
- //
- UiRemoveMenuListEntry (Selection);
-
- Selection->Action = UI_ACTION_REFRESH_FORM;
- Selection->Statement = NULL;
- break;
-
- case CfUiSelect:
- ControlFlag = CfCheckSelection;
-
- Statement = MenuOption->ThisTag;
- if ((Statement->Operand == EFI_IFR_TEXT_OP) ||
- (Statement->Operand == EFI_IFR_DATE_OP) ||
- (Statement->Operand == EFI_IFR_TIME_OP) ||
- (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {
- break;
- }
-
- //
- // Keep highlight on current MenuOption
- //
- Selection->QuestionId = Statement->QuestionId;
-
- switch (Statement->Operand) {
- case EFI_IFR_REF_OP:
- if (Statement->RefDevicePath != 0) {
- //
- // Goto another Hii Package list
- //
- ControlFlag = CfUiReset;
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
-
- StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);
- if (StringPtr == NULL) {
- //
- // No device path string not found, exit
- //
- Selection->Action = UI_ACTION_EXIT;
- Selection->Statement = NULL;
- break;
- }
- BufferSize = StrLen (StringPtr) / 4;
- DevicePath = AllocatePool (BufferSize);
-
- HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr);
- Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath);
- if (Selection->Handle == NULL) {
- //
- // If target Hii Handle not found, exit
- //
- Selection->Action = UI_ACTION_EXIT;
- Selection->Statement = NULL;
- break;
- }
-
- gBS->FreePool (StringPtr);
- gBS->FreePool (DevicePath);
-
- CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));
- Selection->FormId = Statement->RefFormId;
- Selection->QuestionId = Statement->RefQuestionId;
- } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {
- //
- // Goto another Formset, check for uncommitted data
- //
- ControlFlag = CfUiReset;
- Selection->Action = UI_ACTION_REFRESH_FORMSET;
-
- CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));
- Selection->FormId = Statement->RefFormId;
- Selection->QuestionId = Statement->RefQuestionId;
- } else if (Statement->RefFormId != 0) {
- //
- // Goto another form inside this formset,
- //
- Selection->Action = UI_ACTION_REFRESH_FORM;
-
- //
- // Link current form so that we can always go back when someone hits the UiPrevious
- //
- UiAddMenuListEntry (Selection);
-
- Selection->FormId = Statement->RefFormId;
- Selection->QuestionId = Statement->RefQuestionId;
- } else if (Statement->RefQuestionId != 0) {
- //
- // Goto another Question
- //
- Selection->QuestionId = Statement->RefQuestionId;
-
- if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) {
- Selection->Action = UI_ACTION_REFRESH_FORM;
- } else {
- Repaint = TRUE;
- NewLine = TRUE;
- break;
- }
- }
- break;
-
- case EFI_IFR_ACTION_OP:
- //
- // Process the Config string <ConfigResp>
- //
- Status = ProcessQuestionConfig (Selection, Statement);
-
- if (EFI_ERROR (Status)) {
- break;
- }
-
- //
- // The action button may change some Question value, so refresh the form
- //
- Selection->Action = UI_ACTION_REFRESH_FORM;
- break;
-
- case EFI_IFR_RESET_BUTTON_OP:
- //
- // Reset Question to default value specified by DefaultId
- //
- ControlFlag = CfUiDefault;
- DefaultId = Statement->DefaultId;
- break;
-
- default:
- //
- // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
- //
- UpdateKeyHelp (MenuOption, TRUE);
- Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);
-
- if (EFI_ERROR (Status)) {
- Repaint = TRUE;
- NewLine = TRUE;
- break;
- }
-
- if (OptionString != NULL) {
- PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);
- gBS->FreePool (OptionString);
- }
-
- Selection->Action = UI_ACTION_REFRESH_FORM;
- break;
- }
- break;
-
- case CfUiReset:
- //
- // We are going to leave current FormSet, so check uncommited data in this FormSet
- //
- ControlFlag = CfCheckSelection;
-
- if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
- //
- // There is no parent menu for FrontPage
- //
- Selection->Action = UI_ACTION_NONE;
- Selection->Statement = MenuOption->ThisTag;
- break;
- }
-
- //
- // If NV flag is up, prompt user
- //
- if (gNvUpdateRequired) {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-
- YesResponse = gYesResponse[0];
- NoResponse = gNoResponse[0];
-
- do {
- CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);
- } while
- (
- (Key.ScanCode != SCAN_ESC) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
- ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
- );
-
- //
- // If the user hits the YesResponse key
- //
- if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
- } else {
- Repaint = TRUE;
- NewLine = TRUE;
-
- Selection->Action = UI_ACTION_NONE;
- break;
- }
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-
- UiFreeMenuList ();
- gST->ConOut->ClearScreen (gST->ConOut);
- return EFI_SUCCESS;
-
- case CfUiLeft:
- ControlFlag = CfCheckSelection;
- if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
- if (MenuOption->Sequence != 0) {
- //
- // In the middle or tail of the Date/Time op-code set, go left.
- //
- NewPos = NewPos->BackLink;
- }
- }
- break;
-
- case CfUiRight:
- ControlFlag = CfCheckSelection;
- if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
- if (MenuOption->Sequence != 2) {
- //
- // In the middle or tail of the Date/Time op-code set, go left.
- //
- NewPos = NewPos->ForwardLink;
- }
- }
- break;
-
- case CfUiUp:
- ControlFlag = CfCheckSelection;
-
- SavedListEntry = TopOfScreen;
-
- if (NewPos->BackLink != &Menu) {
- NewLine = TRUE;
- //
- // Adjust Date/Time position before we advance forward.
- //
- AdjustDateAndTimePosition (TRUE, &NewPos);
-
- //
- // Caution that we have already rewind to the top, don't go backward in this situation.
- //
- if (NewPos->BackLink != &Menu) {
- NewPos = NewPos->BackLink;
- }
-
- PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);
- DistanceValue = PreviousMenuOption->Skip;
-
- //
- // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
- // to be one that back to the previous set of op-codes, we need to advance to the sencond
- // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
- // checking can be done.
- //
- DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);
-
- //
- // Check the previous menu entry to see if it was a zero-length advance. If it was,
- // don't worry about a redraw.
- //
- if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {
- Repaint = TRUE;
- TopOfScreen = NewPos;
- }
-
- Difference = MoveToNextStatement (TRUE, &NewPos);
- if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {
- if (Difference > 0) {
- //
- // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
- //
- TopOfScreen = NewPos;
- Repaint = TRUE;
- }
- }
- if (Difference < 0) {
- //
- // We want to goto previous MenuOption, but finally we go down.
- // it means that we hit the begining MenuOption that can be focused
- // so we simply scroll to the top
- //
- if (SavedListEntry != Menu.ForwardLink) {
- TopOfScreen = Menu.ForwardLink;
- Repaint = TRUE;
- }
- }
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
-
- UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
- } else {
- SavedMenuOption = MenuOption;
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- if (!IsSelectable (MenuOption)) {
- //
- // If we are at the end of the list and sitting on a text op, we need to more forward
- //
- ScreenOperation = UiDown;
- ControlFlag = CfScreenOperation;
- break;
- }
-
- MenuOption = SavedMenuOption;
- }
- break;
-
- case CfUiPageUp:
- ControlFlag = CfCheckSelection;
-
- if (NewPos->BackLink == &Menu) {
- NewLine = FALSE;
- Repaint = FALSE;
- break;
- }
-
- NewLine = TRUE;
- Repaint = TRUE;
- Link = TopOfScreen;
- PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index = BottomRow;
- while ((Index >= TopRow) && (Link->BackLink != &Menu)) {
- Index = Index - PreviousMenuOption->Skip;
- Link = Link->BackLink;
- PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
- }
-
- TopOfScreen = Link;
- Difference = MoveToNextStatement (TRUE, &Link);
- if (Difference > 0) {
- //
- // The focus MenuOption is above the TopOfScreen
- //
- TopOfScreen = Link;
- } else if (Difference < 0) {
- //
- // This happens when there is no MenuOption can be focused from
- // Current MenuOption to the first MenuOption
- //
- TopOfScreen = Menu.ForwardLink;
- }
- Index += Difference;
- if (Index < TopRow) {
- MenuOption = NULL;
- }
-
- if (NewPos == Link) {
- Repaint = FALSE;
- NewLine = FALSE;
- } else {
- NewPos = Link;
- }
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- // Don't do this when we are already in the first page.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
- break;
-
- case CfUiPageDown:
- ControlFlag = CfCheckSelection;
-
- if (NewPos->ForwardLink == &Menu) {
- NewLine = FALSE;
- Repaint = FALSE;
- break;
- }
-
- NewLine = TRUE;
- Repaint = TRUE;
- Link = TopOfScreen;
- NextMenuOption = MENU_OPTION_FROM_LINK (Link);
- Index = TopRow;
- while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {
- Index = Index + NextMenuOption->Skip;
- Link = Link->ForwardLink;
- NextMenuOption = MENU_OPTION_FROM_LINK (Link);
- }
-
- Index += MoveToNextStatement (FALSE, &Link);
- if (Index > BottomRow) {
- //
- // There are more MenuOption needing scrolling
- //
- TopOfScreen = Link;
- MenuOption = NULL;
- }
- if (NewPos == Link && Index <= BottomRow) {
- //
- // Finally we know that NewPos is the last MenuOption can be focused.
- //
- NewLine = FALSE;
- Repaint = FALSE;
- } else {
- NewPos = Link;
- }
-
- //
- // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
- // Don't do this when we are already in the last page.
- //
- AdjustDateAndTimePosition (TRUE, &TopOfScreen);
- AdjustDateAndTimePosition (TRUE, &NewPos);
- break;
-
- case CfUiDown:
- ControlFlag = CfCheckSelection;
- //
- // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
- // to be one that progresses to the next set of op-codes, we need to advance to the last
- // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
- // checking can be done. The only other logic we need to introduce is that if a Date/Time
- // op-code is the last entry in the menu, we need to rewind back to the first op-code of
- // the Date/Time op-code.
- //
- SavedListEntry = NewPos;
- DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos);
-
- if (NewPos->ForwardLink != &Menu) {
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- NewLine = TRUE;
- NewPos = NewPos->ForwardLink;
- NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
- DistanceValue += NextMenuOption->Skip;
- DistanceValue += MoveToNextStatement (FALSE, &NewPos);
- //
- // An option might be multi-line, so we need to reflect that data in the overall skip value
- //
- UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);
-
- Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;
- if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&
- (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
- NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)
- ) {
- Temp ++;
- }
-
- //
- // If we are going to scroll, update TopOfScreen
- //
- if (Temp > BottomRow) {
- do {
- //
- // Is the current top of screen a zero-advance op-code?
- // If so, keep moving forward till we hit a >0 advance op-code
- //
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
- //
- // If bottom op-code is more than one line or top op-code is more than one line
- //
- if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {
- //
- // Is the bottom op-code greater than or equal in size to the top op-code?
- //
- if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {
- //
- // Skip the top op-code
- //
- TopOfScreen = TopOfScreen->ForwardLink;
- Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);
-
- OldSkipValue = Difference;
-
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
- //
- // If we have a remainder, skip that many more op-codes until we drain the remainder
- //
- for (;
- Difference >= (INTN) SavedMenuOption->Skip;
- Difference = Difference - (INTN) SavedMenuOption->Skip
- ) {
- //
- // Since the Difference is greater than or equal to this op-code's skip value, skip it
- //
- TopOfScreen = TopOfScreen->ForwardLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
- if (Difference < (INTN) SavedMenuOption->Skip) {
- Difference = SavedMenuOption->Skip - Difference - 1;
- break;
- } else {
- if (Difference == (INTN) SavedMenuOption->Skip) {
- TopOfScreen = TopOfScreen->ForwardLink;
- SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
- Difference = SavedMenuOption->Skip - Difference;
- break;
- }
- }
- }
- //
- // Since we will act on this op-code in the next routine, and increment the
- // SkipValue, set the skips to one less than what is required.
- //
- SkipValue = Difference - 1;
-
- } else {
- //
- // Since we will act on this op-code in the next routine, and increment the
- // SkipValue, set the skips to one less than what is required.
- //
- SkipValue = OldSkipValue + (Temp - BottomRow) - 1;
- }
- } else {
- if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {
- TopOfScreen = TopOfScreen->ForwardLink;
- break;
- } else {
- SkipValue = OldSkipValue;
- }
- }
- //
- // If the op-code at the top of the screen is more than one line, let's not skip it yet
- // Let's set a skip flag to smoothly scroll the top of the screen.
- //
- if (SavedMenuOption->Skip > 1) {
- if (SavedMenuOption == NextMenuOption) {
- SkipValue = 0;
- } else {
- SkipValue++;
- }
- } else {
- SkipValue = 0;
- TopOfScreen = TopOfScreen->ForwardLink;
- }
- } while (SavedMenuOption->Skip == 0);
-
- Repaint = TRUE;
- OldSkipValue = SkipValue;
- }
-
- MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
-
- UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
-
- } else {
- SavedMenuOption = MenuOption;
- MenuOption = MENU_OPTION_FROM_LINK (NewPos);
- if (!IsSelectable (MenuOption)) {
- //
- // If we are at the end of the list and sitting on a text op, we need to more forward
- //
- ScreenOperation = UiUp;
- ControlFlag = CfScreenOperation;
- break;
- }
-
- MenuOption = SavedMenuOption;
- //
- // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
- //
- AdjustDateAndTimePosition (TRUE, &NewPos);
- }
- break;
-
- case CfUiSave:
- ControlFlag = CfCheckSelection;
-
- //
- // Submit the form
- //
- Status = SubmitForm (Selection->FormSet, Selection->Form);
-
- if (!EFI_ERROR (Status)) {
- UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
- UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);
- } else {
- do {
- CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);
- } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
- Repaint = TRUE;
- NewLine = TRUE;
- }
- break;
-
- case CfUiDefault:
- ControlFlag = CfCheckSelection;
-
- Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);
-
- if (!EFI_ERROR (Status)) {
- Selection->Action = UI_ACTION_REFRESH_FORM;
-
- //
- // Show NV update flag on status bar
- //
- gNvUpdateRequired = TRUE;
- }
- break;
-
- case CfUiNoOperation:
- ControlFlag = CfCheckSelection;
- break;
-
- case CfExit:
- UiFreeRefreshList ();
-
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
- gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);
- gST->ConOut->EnableCursor (gST->ConOut, TRUE);
- gST->ConOut->OutputString (gST->ConOut, L"\n");
-
- return EFI_SUCCESS;
-
- default:
- break;
- }
- }
-}
+/** @file\r
+Utility functions for User Interface functions.\r
+\r
+Copyright (c) 2004 - 2008, Intel Corporation\r
+All rights reserved. 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
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ui.h"\r
+#include "Setup.h"\r
+\r
+LIST_ENTRY Menu;\r
+LIST_ENTRY gMenuList;\r
+MENU_REFRESH_ENTRY *gMenuRefreshHead;\r
+\r
+//\r
+// Search table for UiDisplayMenu()\r
+//\r
+SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
+ {\r
+ SCAN_UP,\r
+ UiUp,\r
+ },\r
+ {\r
+ SCAN_DOWN,\r
+ UiDown,\r
+ },\r
+ {\r
+ SCAN_PAGE_UP,\r
+ UiPageUp,\r
+ },\r
+ {\r
+ SCAN_PAGE_DOWN,\r
+ UiPageDown,\r
+ },\r
+ {\r
+ SCAN_ESC,\r
+ UiReset,\r
+ },\r
+ {\r
+ SCAN_F2,\r
+ UiPrevious,\r
+ },\r
+ {\r
+ SCAN_LEFT,\r
+ UiLeft,\r
+ },\r
+ {\r
+ SCAN_RIGHT,\r
+ UiRight,\r
+ },\r
+ {\r
+ SCAN_F9,\r
+ UiDefault,\r
+ },\r
+ {\r
+ SCAN_F10,\r
+ UiSave\r
+ }\r
+};\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
+ },\r
+ {\r
+ UiUp,\r
+ CfUiUp,\r
+ },\r
+ {\r
+ UiDown,\r
+ CfUiDown,\r
+ },\r
+ {\r
+ UiLeft,\r
+ CfUiLeft,\r
+ },\r
+ {\r
+ UiRight,\r
+ CfUiRight,\r
+ },\r
+ {\r
+ UiReset,\r
+ CfUiReset,\r
+ },\r
+ {\r
+ UiSave,\r
+ CfUiSave,\r
+ },\r
+ {\r
+ UiPrevious,\r
+ CfUiPrevious,\r
+ },\r
+ {\r
+ UiPageUp,\r
+ CfUiPageUp,\r
+ },\r
+ {\r
+ UiPageDown,\r
+ CfUiPageDown\r
+ }\r
+};\r
+\r
+BOOLEAN mInputError;\r
+BOOLEAN GetLineByWidthFinished = FALSE;\r
+\r
+\r
+/**\r
+ Set Buffer to Value for Size bytes.\r
+\r
+ @param Buffer Memory to set.\r
+ @param Size Number of bytes to set\r
+ @param Value Value of the set operation.\r
+\r
+ @return Value.\r
+\r
+**/\r
+VOID\r
+SetUnicodeMem (\r
+ IN VOID *Buffer,\r
+ IN UINTN Size,\r
+ IN CHAR16 Value\r
+ )\r
+{\r
+ CHAR16 *Ptr;\r
+\r
+ Ptr = Buffer;\r
+ while ((Size--) != 0) {\r
+ *(Ptr++) = Value;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize Menu option list.\r
+\r
+**/\r
+VOID\r
+UiInitMenu (\r
+ VOID\r
+ )\r
+{\r
+ InitializeListHead (&Menu);\r
+}\r
+\r
+\r
+/**\r
+ Initialize Menu option list.\r
+\r
+**/\r
+VOID\r
+UiInitMenuList (\r
+ VOID\r
+ )\r
+{\r
+ InitializeListHead (&gMenuList);\r
+}\r
+\r
+\r
+/**\r
+ Remove a Menu in list, and return FormId/QuestionId for previous Menu.\r
+\r
+ @param Selection Menu selection.\r
+\r
+**/\r
+VOID\r
+UiRemoveMenuListEntry (\r
+ OUT UI_MENU_SELECTION *Selection\r
+ )\r
+{\r
+ UI_MENU_LIST *UiMenuList;\r
+\r
+ if (!IsListEmpty (&gMenuList)) {\r
+ UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+\r
+ Selection->FormId = UiMenuList->FormId;\r
+ Selection->QuestionId = UiMenuList->QuestionId;\r
+ RemoveEntryList (&UiMenuList->MenuLink);\r
+ FreePool (UiMenuList);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+ VOID\r
+ )\r
+{\r
+ UI_MENU_LIST *UiMenuList;\r
+\r
+ while (!IsListEmpty (&gMenuList)) {\r
+ UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+ RemoveEntryList (&UiMenuList->MenuLink);\r
+ FreePool (UiMenuList);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Add one menu entry to the linked lst\r
+\r
+ @param Selection Menu selection.\r
+\r
+**/\r
+VOID\r
+UiAddMenuListEntry (\r
+ IN UI_MENU_SELECTION *Selection\r
+ )\r
+{\r
+ UI_MENU_LIST *UiMenuList;\r
+\r
+ UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
+ ASSERT (UiMenuList != NULL);\r
+\r
+ UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
+ UiMenuList->FormId = Selection->FormId;\r
+ UiMenuList->QuestionId = Selection->QuestionId;\r
+\r
+ InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
+}\r
+\r
+\r
+/**\r
+ Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenu (\r
+ VOID\r
+ )\r
+{\r
+ UI_MENU_OPTION *MenuOption;\r
+\r
+ while (!IsListEmpty (&Menu)) {\r
+ MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
+ RemoveEntryList (&MenuOption->Link);\r
+\r
+ //\r
+ // We allocated space for this description when we did a GetToken, free it here\r
+ //\r
+ if (MenuOption->Skip != 0) {\r
+ //\r
+ // For date/time, MenuOption->Description is shared by three Menu Options\r
+ // Data format : [01/02/2004] [11:22:33]\r
+ // Line number : 0 0 1 0 0 1\r
+ //\r
+ FreePool (MenuOption->Description);\r
+ }\r
+ FreePool (MenuOption);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeRefreshList (\r
+ VOID\r
+ )\r
+{\r
+ MENU_REFRESH_ENTRY *OldMenuRefreshEntry;\r
+\r
+ while (gMenuRefreshHead != NULL) {\r
+ OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
+ FreePool (gMenuRefreshHead);\r
+ gMenuRefreshHead = OldMenuRefreshEntry;\r
+ }\r
+\r
+ gMenuRefreshHead = NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Refresh screen.\r
+\r
+**/\r
+EFI_STATUS\r
+RefreshForm (\r
+ VOID\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
+\r
+ MenuRefreshEntry = gMenuRefreshHead;\r
+\r
+ //\r
+ // Reset FormPackage update flag\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
+\r
+ Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\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
+ // If leading spaces on OptionString - remove the spaces\r
+ //\r
+ for (Index = 0; OptionString[Index] == L' '; Index++)\r
+ ;\r
+\r
+ PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
+ FreePool (OptionString);\r
+ }\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
+ 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
+\r
+ Status = ConfigAccess->Callback (\r
+ ConfigAccess,\r
+ EFI_BROWSER_ACTION_CHANGING,\r
+ Question->QuestionId,\r
+ HiiValue->Type,\r
+ &HiiValue->Value,\r
+ &ActionRequest\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
+ case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
+ SubmitForm (Selection->FormSet, Selection->Form);\r
+ break;\r
+\r
+ case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ gNvUpdateRequired = FALSE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ MenuRefreshEntry = MenuRefreshEntry->Next;\r
+\r
+ } while (MenuRefreshEntry != NULL);\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
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+\r
+/**\r
+ Wait for a given event to fire, or for an optional timeout to expire.\r
+\r
+ @param Event The event to wait for\r
+ @param Timeout An optional timeout value in 100 ns units.\r
+ @param RefreshInterval Menu refresh interval (in seconds).\r
+\r
+ @retval EFI_SUCCESS Event fired before Timeout expired.\r
+ @retval EFI_TIME_OUT Timout expired before Event fired.\r
+\r
+**/\r
+EFI_STATUS\r
+UiWaitForSingleEvent (\r
+ IN EFI_EVENT Event,\r
+ IN UINT64 Timeout, OPTIONAL\r
+ IN UINT8 RefreshInterval OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_EVENT TimerEvent;\r
+ EFI_EVENT WaitList[2];\r
+\r
+ if (Timeout != 0) {\r
+ //\r
+ // Create a timer event\r
+ //\r
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Set the timer event\r
+ //\r
+ gBS->SetTimer (\r
+ TimerEvent,\r
+ TimerRelative,\r
+ Timeout\r
+ );\r
+\r
+ //\r
+ // Wait for the original event or the timer\r
+ //\r
+ WaitList[0] = Event;\r
+ WaitList[1] = TimerEvent;\r
+ Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+ gBS->CloseEvent (TimerEvent);\r
+\r
+ //\r
+ // If the timer expired, change the return to timed out\r
+ //\r
+ if (!EFI_ERROR (Status) && Index == 1) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // Update screen every second\r
+ //\r
+ if (RefreshInterval == 0) {\r
+ Timeout = ONE_SECOND;\r
+ } else {\r
+ Timeout = RefreshInterval * ONE_SECOND;\r
+ }\r
+\r
+ do {\r
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+\r
+ //\r
+ // Set the timer event\r
+ //\r
+ gBS->SetTimer (\r
+ TimerEvent,\r
+ TimerRelative,\r
+ Timeout\r
+ );\r
+\r
+ //\r
+ // Wait for the original event or the timer\r
+ //\r
+ WaitList[0] = Event;\r
+ WaitList[1] = TimerEvent;\r
+ Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+\r
+ //\r
+ // If the timer expired, update anything that needs a refresh and keep waiting\r
+ //\r
+ if (!EFI_ERROR (Status) && Index == 1) {\r
+ Status = EFI_TIMEOUT;\r
+ if (RefreshInterval != 0) {\r
+ Status = RefreshForm ();\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (TimerEvent);\r
+ } while (Status == EFI_TIMEOUT);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add one menu option by specified description and context.\r
+\r
+ @param String String description for this option.\r
+ @param Handle Hii handle for the package list.\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
+\r
+**/\r
+VOID\r
+UiAddMenuOption (\r
+ IN CHAR16 *String,\r
+ IN EFI_HII_HANDLE Handle,\r
+ IN FORM_BROWSER_STATEMENT *Statement,\r
+ IN UINT16 NumberOfLines,\r
+ IN UINT16 MenuItemCount\r
+ )\r
+{\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN Index;\r
+ UINTN Count;\r
+\r
+ Count = 1;\r
+\r
+ if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
+ //\r
+ // Add three MenuOptions for Date/Time\r
+ // Data format : [01/02/2004] [11:22:33]\r
+ // Line number : 0 0 1 0 0 1\r
+ //\r
+ NumberOfLines = 0;\r
+ Count = 3;\r
+\r
+ if (Statement->Storage == NULL) {\r
+ //\r
+ // For RTC type of date/time, set default refresh interval to be 1 second\r
+ //\r
+ if (Statement->RefreshInterval == 0) {\r
+ Statement->RefreshInterval = 1;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
+ ASSERT (MenuOption);\r
+\r
+ MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
+ MenuOption->Description = String;\r
+ MenuOption->Handle = Handle;\r
+ MenuOption->ThisTag = Statement;\r
+ MenuOption->EntryNumber = MenuItemCount;\r
+\r
+ if (Index == 2) {\r
+ //\r
+ // Override LineNumber for the MenuOption in Date/Time sequence\r
+ //\r
+ MenuOption->Skip = 1;\r
+ } else {\r
+ MenuOption->Skip = NumberOfLines;\r
+ }\r
+ MenuOption->Sequence = Index;\r
+\r
+ if (Statement->GrayOutExpression != NULL) {\r
+ MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
+ }\r
+\r
+ if ((Statement->ValueExpression != NULL) ||\r
+ ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
+ MenuOption->ReadOnly = TRUE;\r
+ }\r
+\r
+ InsertTailList (&Menu, &MenuOption->Link);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Routine used to abstract a generic dialog interface and return the selected key or string\r
+\r
+ @param NumberOfLines The number of lines for the dialog box\r
+ @param HotKey Defines whether a single character is parsed\r
+ (TRUE) and returned in KeyValue or a string is\r
+ returned in StringBuffer. Two special characters\r
+ are considered when entering a string, a SCAN_ESC\r
+ and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates\r
+ string input and returns\r
+ @param MaximumStringSize The maximum size in bytes of a typed in string\r
+ (each character is a CHAR16) and the minimum\r
+ string returned is two bytes\r
+ @param StringBuffer The passed in pointer to the buffer which will\r
+ hold the typed in string if HotKey is FALSE\r
+ @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
+ @param ... A series of (quantity == NumberOfLines) text\r
+ strings which will be used to construct the dialog\r
+ box\r
+\r
+ @retval EFI_SUCCESS Displayed dialog and received user interaction\r
+ @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.\r
+ (StringBuffer == NULL) && (HotKey == FALSE))\r
+ @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine\r
+\r
+**/\r
+EFI_STATUS\r
+CreateDialog (\r
+ IN UINTN NumberOfLines,\r
+ IN BOOLEAN HotKey,\r
+ IN UINTN MaximumStringSize,\r
+ OUT CHAR16 *StringBuffer,\r
+ OUT EFI_INPUT_KEY *KeyValue,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ VA_LIST MarkerBackup;\r
+ UINTN Count;\r
+ EFI_INPUT_KEY Key;\r
+ UINTN LargestString;\r
+ CHAR16 *TempString;\r
+ CHAR16 *BufferedString;\r
+ CHAR16 *StackString;\r
+ CHAR16 KeyPad[2];\r
+ UINTN Start;\r
+ UINTN Top;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ BOOLEAN SelectionComplete;\r
+ UINTN InputOffset;\r
+ UINTN CurrentAttribute;\r
+ UINTN DimensionsWidth;\r
+ UINTN DimensionsHeight;\r
+\r
+ DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+ DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+ SelectionComplete = FALSE;\r
+ InputOffset = 0;\r
+ TempString = AllocateZeroPool (MaximumStringSize * 2);\r
+ BufferedString = AllocateZeroPool (MaximumStringSize * 2);\r
+ CurrentAttribute = gST->ConOut->Mode->Attribute;\r
+\r
+ ASSERT (TempString);\r
+ ASSERT (BufferedString);\r
+\r
+ VA_START (Marker, KeyValue);\r
+ MarkerBackup = Marker;\r
+\r
+ //\r
+ // Zero the outgoing buffer\r
+ //\r
+ ZeroMem (StringBuffer, MaximumStringSize);\r
+\r
+ if (HotKey) {\r
+ if (KeyValue == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ if (StringBuffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Disable cursor\r
+ //\r
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+ LargestString = 0;\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
+ //\r
+ for (Count = 0; Count < NumberOfLines; Count++) {\r
+ StackString = VA_ARG (Marker, CHAR16 *);\r
+\r
+ if (StackString[0] == L' ') {\r
+ InputOffset = Count + 1;\r
+ }\r
+\r
+ if ((GetStringWidth (StackString) / 2) > LargestString) {\r
+ //\r
+ // Size of the string visually and subtract the width by one for the null-terminator\r
+ //\r
+ LargestString = (GetStringWidth (StackString) / 2);\r
+ }\r
+ }\r
+\r
+ Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
+ Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
+\r
+ Count = 0;\r
+\r
+ //\r
+ // Display the Popup\r
+ //\r
+ CreateSharedPopUp (LargestString, NumberOfLines, MarkerBackup);\r
+\r
+ //\r
+ // Take the first key typed and report it back?\r
+ //\r
+ if (HotKey) {\r
+ Status = WaitForKeyStroke (&Key);\r
+ ASSERT_EFI_ERROR (Status);\r
+ CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
+\r
+ } else {\r
+ do {\r
+ Status = WaitForKeyStroke (&Key);\r
+\r
+ switch (Key.UnicodeChar) {\r
+ case CHAR_NULL:\r
+ switch (Key.ScanCode) {\r
+ case SCAN_ESC:\r
+ FreePool (TempString);\r
+ FreePool (BufferedString);\r
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ break;\r
+\r
+ case CHAR_CARRIAGE_RETURN:\r
+ SelectionComplete = TRUE;\r
+ FreePool (TempString);\r
+ FreePool (BufferedString);\r
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+ return EFI_SUCCESS;\r
+ break;\r
+\r
+ case CHAR_BACKSPACE:\r
+ if (StringBuffer[0] != CHAR_NULL) {\r
+ for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
+ TempString[Index] = StringBuffer[Index];\r
+ }\r
+ //\r
+ // Effectively truncate string by 1 character\r
+ //\r
+ TempString[Index - 1] = CHAR_NULL;\r
+ StrCpy (StringBuffer, TempString);\r
+ }\r
+\r
+ default:\r
+ //\r
+ // If it is the beginning of the string, don't worry about checking maximum limits\r
+ //\r
+ if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+ StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
+ StrnCpy (TempString, &Key.UnicodeChar, 1);\r
+ } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+ KeyPad[0] = Key.UnicodeChar;\r
+ KeyPad[1] = CHAR_NULL;\r
+ StrCat (StringBuffer, KeyPad);\r
+ StrCat (TempString, KeyPad);\r
+ }\r
+ //\r
+ // If the width of the input string is now larger than the screen, we nee to\r
+ // adjust the index to start printing portions of the string\r
+ //\r
+ SetUnicodeMem (BufferedString, LargestString, L' ');\r
+\r
+ PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
+\r
+ if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
+ Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
+ } else {\r
+ Index = 0;\r
+ }\r
+\r
+ for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
+ BufferedString[Count] = StringBuffer[Index];\r
+ }\r
+\r
+ PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
+ break;\r
+ }\r
+ } while (!SelectionComplete);\r
+ }\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Draw a pop up windows based on the dimension, number of lines and\r
+ strings specified.\r
+\r
+ @param RequestedWidth The width of the pop-up.\r
+ @param NumberOfLines The number of lines.\r
+ @param Marker The variable argument list for the list of string to be printed.\r
+\r
+**/\r
+VOID\r
+CreateSharedPopUp (\r
+ IN UINTN RequestedWidth,\r
+ IN UINTN NumberOfLines,\r
+ IN VA_LIST Marker\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Count;\r
+ CHAR16 Character;\r
+ UINTN Start;\r
+ UINTN End;\r
+ UINTN Top;\r
+ UINTN Bottom;\r
+ CHAR16 *String;\r
+ UINTN DimensionsWidth;\r
+ UINTN DimensionsHeight;\r
+\r
+ DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+ DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+\r
+ if ((RequestedWidth + 2) > DimensionsWidth) {\r
+ RequestedWidth = DimensionsWidth - 2;\r
+ }\r
+\r
+ //\r
+ // Subtract the PopUp width from total Columns, allow for one space extra on\r
+ // each end plus a border.\r
+ //\r
+ Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
+ End = Start + RequestedWidth + 1;\r
+\r
+ Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
+ Bottom = Top + NumberOfLines + 2;\r
+\r
+ Character = BOXDRAW_DOWN_RIGHT;\r
+ PrintCharAt (Start, Top, Character);\r
+ Character = BOXDRAW_HORIZONTAL;\r
+ for (Index = Start; Index + 2 < End; Index++) {\r
+ PrintChar (Character);\r
+ }\r
+\r
+ Character = BOXDRAW_DOWN_LEFT;\r
+ PrintChar (Character);\r
+ Character = BOXDRAW_VERTICAL;\r
+\r
+ Count = 0;\r
+ for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
+ String = VA_ARG (Marker, CHAR16*);\r
+\r
+ //\r
+ // This will clear the background of the line - we never know who might have been\r
+ // here before us. This differs from the next clear in that it used the non-reverse\r
+ // video for normal printing.\r
+ //\r
+ if (GetStringWidth (String) / 2 > 1) {\r
+ ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
+ }\r
+\r
+ //\r
+ // Passing in a space results in the assumption that this is where typing will occur\r
+ //\r
+ if (String[0] == L' ') {\r
+ ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
+ }\r
+\r
+ //\r
+ // Passing in a NULL results in a blank space\r
+ //\r
+ if (String[0] == CHAR_NULL) {\r
+ ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
+ }\r
+\r
+ PrintStringAt (\r
+ ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
+ Index + 1,\r
+ String\r
+ );\r
+ gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+ PrintCharAt (Start, Index + 1, Character);\r
+ PrintCharAt (End - 1, Index + 1, Character);\r
+ }\r
+\r
+ Character = BOXDRAW_UP_RIGHT;\r
+ PrintCharAt (Start, Bottom - 1, Character);\r
+ Character = BOXDRAW_HORIZONTAL;\r
+ for (Index = Start; Index + 2 < End; Index++) {\r
+ PrintChar (Character);\r
+ }\r
+\r
+ Character = BOXDRAW_UP_LEFT;\r
+ PrintChar (Character);\r
+}\r
+\r
+/**\r
+ Draw a pop up windows based on the dimension, number of lines and\r
+ strings specified.\r
+\r
+ @param RequestedWidth The width of the pop-up.\r
+ @param NumberOfLines The number of lines.\r
+ @param ... A series of text strings that displayed in the pop-up.\r
+\r
+**/\r
+VOID\r
+CreatePopUp (\r
+ IN UINTN RequestedWidth,\r
+ IN UINTN NumberOfLines,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+\r
+ VA_START (Marker, NumberOfLines);\r
+ \r
+ CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
+\r
+ VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+ Update status bar on the bottom of menu.\r
+\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
+**/\r
+VOID\r
+UpdateStatusBar (\r
+ IN UINTN MessageType,\r
+ IN UINT8 Flags,\r
+ IN BOOLEAN State\r
+ )\r
+{\r
+ UINTN Index;\r
+ CHAR16 *NvUpdateMessage;\r
+ CHAR16 *InputErrorMessage;\r
+\r
+ NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
+ InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
+\r
+ switch (MessageType) {\r
+ case INPUT_ERROR:\r
+ if (State) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
+ PrintStringAt (\r
+ gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
+ gScreenDimensions.BottomRow - 1,\r
+ InputErrorMessage\r
+ );\r
+ mInputError = TRUE;\r
+ } else {\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
+ for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
+ PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");\r
+ }\r
+\r
+ mInputError = FALSE;\r
+ }\r
+ break;\r
+\r
+ case NV_UPDATE_REQUIRED:\r
+ if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
+ if (State) {\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
+ }\r
+ break;\r
+\r
+ case REFRESH_STATUS_BAR:\r
+ if (mInputError) {\r
+ UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
+ }\r
+\r
+ if (gNvUpdateRequired) {\r
+ UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ FreePool (InputErrorMessage);\r
+ FreePool (NvUpdateMessage);\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Get the supported width for a particular op-code\r
+\r
+ @param Statement The FORM_BROWSER_STATEMENT structure passed in.\r
+ @param Handle The handle in the HII database being used\r
+\r
+ @return Returns the number of CHAR16 characters that is support.\r
+\r
+**/\r
+UINT16\r
+GetWidth (\r
+ IN FORM_BROWSER_STATEMENT *Statement,\r
+ IN EFI_HII_HANDLE Handle\r
+ )\r
+{\r
+ CHAR16 *String;\r
+ UINTN Size;\r
+ UINT16 Width;\r
+\r
+ Size = 0;\r
+\r
+ //\r
+ // See if the second text parameter is really NULL\r
+ //\r
+ if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
+ String = GetToken (Statement->TextTwo, Handle);\r
+ Size = StrLen (String);\r
+ FreePool (String);\r
+ }\r
+\r
+ if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||\r
+ (Statement->Operand == EFI_IFR_REF_OP) ||\r
+ (Statement->Operand == EFI_IFR_PASSWORD_OP) ||\r
+ (Statement->Operand == EFI_IFR_ACTION_OP) ||\r
+ (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
+ //\r
+ // Allow a wide display if text op-code and no secondary text op-code\r
+ //\r
+ ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))\r
+ ) {\r
+ Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
+ } else {\r
+ Width = (UINT16) gPromptBlockWidth;\r
+ }\r
+\r
+ if (Statement->InSubtitle) {\r
+ Width -= SUBTITLE_INDENT;\r
+ }\r
+\r
+ return Width;\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
+\r
+ @param InputString String description for this option.\r
+ @param LineWidth Width of the desired string to extract in CHAR16\r
+ characters\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
+\r
+**/\r
+UINT16\r
+GetLineByWidth (\r
+ IN CHAR16 *InputString,\r
+ IN UINT16 LineWidth,\r
+ IN OUT UINTN *Index,\r
+ OUT CHAR16 **OutputString\r
+ )\r
+{\r
+ UINT16 Count;\r
+ UINT16 Count2;\r
+\r
+ if (GetLineByWidthFinished) {\r
+ GetLineByWidthFinished = FALSE;\r
+ return (UINT16) 0;\r
+ }\r
+\r
+ Count = LineWidth;\r
+ Count2 = 0;\r
+\r
+ *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
+\r
+ //\r
+ // Ensure we have got a valid buffer\r
+ //\r
+ if (*OutputString != NULL) {\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
+\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
+\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
+ //\r
+ if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
+ (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
+ ) {\r
+ //\r
+ // Convert to CHAR16 value and show that we are done with this operation\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
+ }\r
+\r
+ CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
+\r
+ //\r
+ // If currently pointing to a space, increment the index to the first non-space character\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
+ } else {\r
+ return (UINT16) 0;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Update display lines for a Menu Option.\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
+ )\r
+{\r
+ UINTN Index;\r
+ UINT16 Width;\r
+ UINTN Row;\r
+ UINTN OriginalRow;\r
+ CHAR16 *OutputString;\r
+ CHAR16 *OptionString;\r
+\r
+ Row = 0;\r
+ OptionString = *OptionalString;\r
+ OutputString = NULL;\r
+\r
+ ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\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
+ //\r
+ // If there is more string to process print on the next row and increment the Skip value\r
+ //\r
+ if (StrLen (&OptionString[Index]) != 0) {\r
+ if (SkipValue == 0) {\r
+ Row++;\r
+ //\r
+ // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+ // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+ // some testing to ensure we are keeping this in-sync.\r
+ //\r
+ // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+ //\r
+ if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+ MenuOption->Skip++;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (OutputString);\r
+ if (SkipValue != 0) {\r
+ SkipValue--;\r
+ }\r
+ }\r
+\r
+ Row = OriginalRow;\r
+ }\r
+\r
+ *OptionalString = OptionString;\r
+}\r
+\r
+\r
+/**\r
+ Check whether this Menu Option could be highlighted.\r
+\r
+ This is an internal function.\r
+\r
+ @param MenuOption The MenuOption to be checked.\r
+\r
+ @retval TRUE This Menu Option is selectable.\r
+ @retval FALSE This Menu Option could not be selected.\r
+\r
+**/\r
+BOOLEAN\r
+IsSelectable (\r
+ UI_MENU_OPTION *MenuOption\r
+ )\r
+{\r
+ if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
+ MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Determine if the menu is the last menu that can be selected.\r
+\r
+ This is an internal function.\r
+ \r
+ @param Direction The scroll direction. False is down. True is up.\r
+ @param CurrentPos The current focus.\r
+\r
+ @return FALSE -- the menu isn't the last menu that can be selected.\r
+ @return TRUE -- the menu is the last menu that can be selected.\r
+\r
+**/\r
+BOOLEAN\r
+ValueIsScroll (\r
+ IN BOOLEAN Direction,\r
+ IN LIST_ENTRY *CurrentPos\r
+ )\r
+{\r
+ LIST_ENTRY *Temp;\r
+ UI_MENU_OPTION *MenuOption;\r
+\r
+ Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
+\r
+ if (Temp == &Menu) {\r
+ return TRUE;\r
+ }\r
+\r
+ for (; Temp != &Menu; 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
+}\r
+\r
+\r
+/**\r
+ Move to next selectable statement.\r
+ \r
+ This is an internal function.\r
+ \r
+ @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
+ @param CurrentPosition Current position.\r
+\r
+ @return The row distance from current MenuOption to next selectable MenuOption.\r
+\r
+**/\r
+INTN\r
+MoveToNextStatement (\r
+ IN BOOLEAN GoUp,\r
+ IN OUT LIST_ENTRY **CurrentPosition\r
+ )\r
+{\r
+ INTN Distance;\r
+ LIST_ENTRY *Pos;\r
+ BOOLEAN HitEnd;\r
+ UI_MENU_OPTION *NextMenuOption;\r
+\r
+ Distance = 0;\r
+ Pos = *CurrentPosition;\r
+ HitEnd = FALSE;\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) == &Menu) {\r
+ HitEnd = TRUE;\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
+ //\r
+ Distance = 0;\r
+ Pos = *CurrentPosition;\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) == &Menu) {\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ Distance -= NextMenuOption->Skip;\r
+ Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+ }\r
+ }\r
+\r
+ *CurrentPosition = &NextMenuOption->Link;\r
+ return Distance;\r
+}\r
+\r
+\r
+/**\r
+ Adjust Data and Time position accordingly.\r
+ Data format : [01/02/2004] [11:22:33]\r
+ Line number : 0 0 1 0 0 1\r
+ \r
+ This is an internal function.\r
+\r
+ @param DirectionUp the up or down direction. False is down. True is\r
+ up.\r
+ @param CurrentPosition Current position. On return: Point to the last\r
+ Option (Year or Second) if up; Point to the first\r
+ Option (Month or Hour) if down.\r
+\r
+ @return Return line number to pad. It is possible that we stand on a zero-advance\r
+ @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
+\r
+**/\r
+UINTN\r
+AdjustDateAndTimePosition (\r
+ IN BOOLEAN DirectionUp,\r
+ IN OUT LIST_ENTRY **CurrentPosition\r
+ )\r
+{\r
+ UINTN Count;\r
+ LIST_ENTRY *NewPosition;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UINTN PadLineNumber;\r
+\r
+ PadLineNumber = 0;\r
+ NewPosition = *CurrentPosition;\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
+\r
+ if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
+ (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+ //\r
+ // Calculate the distance from current position to the last Date/Time MenuOption\r
+ //\r
+ Count = 0;\r
+ while (MenuOption->Skip == 0) {\r
+ Count++;\r
+ NewPosition = NewPosition->ForwardLink;\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
+ PadLineNumber = 1;\r
+ }\r
+\r
+ NewPosition = *CurrentPosition;\r
+ if (DirectionUp) {\r
+ //\r
+ // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
+ // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
+ // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
+ // checking can be done.\r
+ //\r
+ while (Count++ < 2) {\r
+ NewPosition = NewPosition->BackLink;\r
+ }\r
+ } else {\r
+ //\r
+ // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
+ // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
+ // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
+ // checking can be done.\r
+ //\r
+ while (Count-- > 0) {\r
+ NewPosition = NewPosition->ForwardLink;\r
+ }\r
+ }\r
+\r
+ *CurrentPosition = NewPosition;\r
+ }\r
+\r
+ return PadLineNumber;\r
+}\r
+\r
+/**\r
+ Find HII Handle in the HII database associated with given Device Path.\r
+\r
+ If DevicePath is NULL, then ASSERT.\r
+\r
+ @param DevicePath Device Path 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
+EFIAPI\r
+DevicePathToHiiHandle (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
+ UINTN BufferSize;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_HANDLE Handle;\r
+ EFI_HANDLE DriverHandle;\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ EFI_HII_HANDLE HiiHandle;\r
+\r
+ ASSERT (DevicePath != NULL);\r
+\r
+ TmpDevicePath = DevicePath;\r
+ //\r
+ // Locate Device Path Protocol handle buffer\r
+ //\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiDevicePathProtocolGuid,\r
+ &TmpDevicePath,\r
+ &DriverHandle\r
+ );\r
+ if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Retrieve all HII Handles from HII database\r
+ //\r
+ BufferSize = 0x1000;\r
+ HiiHandles = AllocatePool (BufferSize);\r
+ ASSERT (HiiHandles != NULL);\r
+ Status = mHiiDatabase->ListPackageLists (\r
+ mHiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferSize,\r
+ HiiHandles\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ FreePool (HiiHandles);\r
+ HiiHandles = AllocatePool (BufferSize);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ Status = mHiiDatabase->ListPackageLists (\r
+ mHiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferSize,\r
+ HiiHandles\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (HiiHandles);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Search Hii Handle by Driver Handle\r
+ //\r
+ HiiHandle = NULL;\r
+ HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = mHiiDatabase->GetPackageListHandle (\r
+ mHiiDatabase,\r
+ HiiHandles[Index],\r
+ &Handle\r
+ );\r
+ if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HiiHandles);\r
+ return HiiHandle;\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
+ after period of time, it will automatically return the first menu option.\r
+\r
+ @param Selection Menu selection.\r
+\r
+ @retval EFI_SUCESSS This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+UiDisplayMenu (\r
+ IN OUT UI_MENU_SELECTION *Selection\r
+ )\r
+{\r
+ INTN SkipValue;\r
+ INTN Difference;\r
+ INTN OldSkipValue;\r
+ UINTN DistanceValue;\r
+ UINTN Row;\r
+ UINTN Col;\r
+ UINTN Temp;\r
+ UINTN Temp2;\r
+ UINTN TopRow;\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
+ BOOLEAN NewLine;\r
+ BOOLEAN Repaint;\r
+ BOOLEAN SavedValue;\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NewPos;\r
+ LIST_ENTRY *TopOfScreen;\r
+ LIST_ENTRY *SavedListEntry;\r
+ UI_MENU_OPTION *MenuOption;\r
+ UI_MENU_OPTION *NextMenuOption;\r
+ UI_MENU_OPTION *SavedMenuOption;\r
+ UI_MENU_OPTION *PreviousMenuOption;\r
+ UI_CONTROL_FLAG ControlFlag;\r
+ EFI_SCREEN_DESCRIPTOR LocalScreen;\r
+ MENU_REFRESH_ENTRY *MenuRefreshEntry;\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
+\r
+ CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+\r
+ Status = EFI_SUCCESS;\r
+ FormattedString = NULL;\r
+ OptionString = NULL;\r
+ ScreenOperation = UiNoOperation;\r
+ NewLine = TRUE;\r
+ MinRefreshInterval = 0;\r
+ DefaultId = 0;\r
+\r
+ OutputString = NULL;\r
+ gUpArrow = FALSE;\r
+ gDownArrow = FALSE;\r
+ SkipValue = 0;\r
+ OldSkipValue = 0;\r
+ MenuRefreshEntry = gMenuRefreshHead;\r
+\r
+ NextMenuOption = NULL;\r
+ PreviousMenuOption = NULL;\r
+ SavedMenuOption = NULL;\r
+\r
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
+\r
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
+ TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+ Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+ } else {\r
+ TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\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
+\r
+ Selection->TopRow = TopRow;\r
+ Selection->BottomRow = BottomRow;\r
+ Selection->PromptCol = Col;\r
+ Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+ Selection->Statement = NULL;\r
+\r
+ TopOfScreen = Menu.ForwardLink;\r
+ Repaint = TRUE;\r
+ MenuOption = NULL;\r
+\r
+ //\r
+ // Get user's selection\r
+ //\r
+ NewPos = Menu.ForwardLink;\r
+\r
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+ UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
+\r
+ ControlFlag = CfInitialization;\r
+ Selection->Action = UI_ACTION_NONE;\r
+ while (TRUE) {\r
+ switch (ControlFlag) {\r
+ case CfInitialization:\r
+ if (IsListEmpty (&Menu)) {\r
+ ControlFlag = CfReadKey;\r
+ } else {\r
+ ControlFlag = CfCheckSelection;\r
+ }\r
+ break;\r
+\r
+ case CfCheckSelection:\r
+ if (Selection->Action != UI_ACTION_NONE) {\r
+ ControlFlag = CfExit;\r
+ } else {\r
+ ControlFlag = CfRepaint;\r
+ }\r
+ break;\r
+\r
+ case CfRepaint:\r
+ ControlFlag = CfRefreshHighLight;\r
+\r
+ if (Repaint) {\r
+ //\r
+ // Display menu\r
+ //\r
+ gDownArrow = FALSE;\r
+ gUpArrow = 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
+\r
+ UiFreeRefreshList ();\r
+ MinRefreshInterval = 0;\r
+\r
+ for (Link = TopOfScreen; Link != &Menu; 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
+\r
+ Statement = MenuOption->ThisTag;\r
+ if (Statement->InSubtitle) {\r
+ MenuOption->Col += SUBTITLE_INDENT;\r
+ }\r
+\r
+ if (MenuOption->GrayOut) {\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
+ }\r
+ }\r
+\r
+ Width = GetWidth (Statement, MenuOption->Handle);\r
+ OriginalRow = Row;\r
+\r
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+ if ((Temp == 0) && (Row <= BottomRow)) {\r
+ PrintStringAt (MenuOption->Col, Row, OutputString);\r
+ }\r
+ //\r
+ // If there is more string to process print on the next row and increment the Skip value\r
+ //\r
+ if (StrLen (&MenuOption->Description[Index]) != 0) {\r
+ if (Temp == 0) {\r
+ Row++;\r
+ }\r
+ }\r
+\r
+ FreePool (OutputString);\r
+ if (Temp != 0) {\r
+ Temp--;\r
+ }\r
+ }\r
+\r
+ Temp = 0;\r
+ Row = OriginalRow;\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Repaint to clear possible error prompt pop-up\r
+ //\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ ControlFlag = CfRepaint;\r
+ break;\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
+ }\r
+\r
+ Width = (UINT16) gOptionBlockWidth;\r
+ OriginalRow = Row;\r
+\r
+ for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+ if ((Temp2 == 0) && (Row <= BottomRow)) {\r
+ PrintStringAt (MenuOption->OptCol, 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
+ 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 (Temp2 != 0) {\r
+ Temp2--;\r
+ }\r
+ }\r
+\r
+ Temp2 = 0;\r
+ Row = OriginalRow;\r
+\r
+ FreePool (OptionString);\r
+ }\r
+ //\r
+ // If this is a text op with secondary text information\r
+ //\r
+ if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
+ StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
+\r
+ Width = (UINT16) gOptionBlockWidth;\r
+ OriginalRow = Row;\r
+\r
+ for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
+ if ((Temp == 0) && (Row <= BottomRow)) {\r
+ PrintStringAt (MenuOption->OptCol, 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 (&StringPtr[Index]) != 0) {\r
+ if (Temp2 == 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 (Temp2 != 0) {\r
+ Temp2--;\r
+ }\r
+ }\r
+\r
+ Row = OriginalRow;\r
+ FreePool (StringPtr);\r
+ }\r
+\r
+ //\r
+ // Need to handle the bottom of the display\r
+ //\r
+ if (MenuOption->Skip > 1) {\r
+ Row += MenuOption->Skip - SkipValue;\r
+ SkipValue = 0;\r
+ } else {\r
+ Row += MenuOption->Skip;\r
+ }\r
+\r
+ if (Row > BottomRow) {\r
+ if (!ValueIsScroll (FALSE, Link)) {\r
+ gDownArrow = TRUE;\r
+ }\r
+\r
+ Row = BottomRow + 1;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
+ gUpArrow = TRUE;\r
+ }\r
+\r
+ if (gUpArrow) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
+ PrintAt (\r
+ LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+ TopRow - SCROLL_ARROW_HEIGHT,\r
+ L"%c",\r
+ ARROW_UP\r
+ );\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ }\r
+\r
+ if (gDownArrow) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
+ PrintAt (\r
+ LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+ BottomRow + SCROLL_ARROW_HEIGHT,\r
+ L"%c",\r
+ ARROW_DOWN\r
+ );\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ }\r
+\r
+ MenuOption = NULL;\r
+ }\r
+ break;\r
+\r
+ case CfRefreshHighLight:\r
+ //\r
+ // MenuOption: Last menu option that need to remove hilight\r
+ // MenuOption is set to NULL in Repaint\r
+ // NewPos: Current menu option that need to hilight\r
+ //\r
+ ControlFlag = CfUpdateHelpString;\r
+\r
+ //\r
+ // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
+ // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
+ //\r
+ SavedValue = Repaint;\r
+ Repaint = FALSE;\r
+\r
+ if (Selection->QuestionId != 0) {\r
+ NewPos = Menu.ForwardLink;\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+ while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {\r
+ NewPos = NewPos->ForwardLink;\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ }\r
+ if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
+ //\r
+ // Target Question found, find its MenuOption\r
+ //\r
+ Link = TopOfScreen;\r
+\r
+ for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ Index += SavedMenuOption->Skip;\r
+ Link = Link->ForwardLink;\r
+ }\r
+\r
+ if (Link != NewPos || Index > BottomRow) {\r
+ //\r
+ // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
+ //\r
+ Link = NewPos;\r
+ for (Index = TopRow; Index <= BottomRow; ) {\r
+ Link = Link->BackLink;\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ Index += SavedMenuOption->Skip;\r
+ }\r
+ TopOfScreen = Link->ForwardLink;\r
+\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ ControlFlag = CfRepaint;\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // Target Question not found, highlight the default menu option\r
+ //\r
+ NewPos = TopOfScreen;\r
+ }\r
+\r
+ Selection->QuestionId = 0;\r
+ }\r
+\r
+ if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
+ if (MenuOption != NULL) {\r
+ //\r
+ // Remove highlight on last Menu Option\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
+ 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
+ }\r
+\r
+ Width = (UINT16) gOptionBlockWidth;\r
+ OriginalRow = MenuOption->Row;\r
+\r
+ for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+ if (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
+ }\r
+\r
+ FreePool (OutputString);\r
+ }\r
+\r
+ MenuOption->Row = OriginalRow;\r
+\r
+ FreePool (OptionString);\r
+ } else {\r
+ if (NewLine) {\r
+ if (MenuOption->GrayOut) {\r
+ gST->ConOut->SetAttribute (gST->ConOut, 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
+ }\r
+\r
+ OriginalRow = MenuOption->Row;\r
+ Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+\r
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+ if (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
+ }\r
+\r
+ FreePool (OutputString);\r
+ }\r
+\r
+ MenuOption->Row = OriginalRow;\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | 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
+ //\r
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+ if (!IsSelectable (MenuOption)) {\r
+ ASSERT (ScreenOperation == UiNoOperation);\r
+ ScreenOperation = UiDown;\r
+ ControlFlag = CfScreenOperation;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // This is the current selected statement\r
+ //\r
+ Statement = MenuOption->ThisTag;\r
+ Selection->Statement = Statement;\r
+\r
+ //\r
+ // Set reverse attribute\r
+ //\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+\r
+ //\r
+ // Assuming that we have a refresh linked-list created, lets annotate the\r
+ // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
+ // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\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 == MenuOption) {\r
+ MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
+ }\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
+ }\r
+ Width = (UINT16) gOptionBlockWidth;\r
+\r
+ OriginalRow = MenuOption->Row;\r
+\r
+ for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+ if (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
+ }\r
+\r
+ FreePool (OutputString);\r
+ }\r
+\r
+ MenuOption->Row = OriginalRow;\r
+\r
+ FreePool (OptionString);\r
+ } else {\r
+ if (NewLine) {\r
+ OriginalRow = MenuOption->Row;\r
+\r
+ Width = GetWidth (Statement, MenuOption->Handle);\r
+\r
+ for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+ if (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
+ }\r
+\r
+ FreePool (OutputString);\r
+ }\r
+\r
+ MenuOption->Row = OriginalRow;\r
+\r
+ }\r
+ }\r
+\r
+ UpdateKeyHelp (MenuOption, FALSE);\r
+\r
+ //\r
+ // Clear reverse attribute\r
+ //\r
+ gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+ }\r
+ //\r
+ // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
+ // if we didn't break halfway when process CfRefreshHighLight.\r
+ //\r
+ Repaint = SavedValue;\r
+ break;\r
+\r
+ case CfUpdateHelpString:\r
+ ControlFlag = CfPrepareToReadKey;\r
+\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
+ 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
+ //\r
+ // Pad String with spaces to simulate a clearing of the previous line\r
+ //\r
+ for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
+ StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
+ }\r
+\r
+ PrintStringAt (\r
+ LocalScreen.RightColumn - gHelpBlockWidth,\r
+ Index + TopRow,\r
+ &FormattedString[Index * gHelpBlockWidth * 2]\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Reset this flag every time we finish using it.\r
+ //\r
+ Repaint = FALSE;\r
+ NewLine = FALSE;\r
+ break;\r
+\r
+ case CfPrepareToReadKey:\r
+ ControlFlag = CfReadKey;\r
+ ScreenOperation = UiNoOperation;\r
+ break;\r
+\r
+ case CfReadKey:\r
+ ControlFlag = CfScreenOperation;\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
+\r
+ if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
+ //\r
+ // IFR is updated in Callback of refresh opcode, re-parse it\r
+ //\r
+ ControlFlag = CfUiReset;\r
+ Selection->Statement = NULL;\r
+ break;\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
+ break;\r
+ }\r
+\r
+ if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {\r
+ //\r
+ // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
+ //\r
+ break;\r
+ }\r
+\r
+ switch (Key.UnicodeChar) {\r
+ case CHAR_CARRIAGE_RETURN:\r
+ ScreenOperation = UiSelect;\r
+ gDirection = 0;\r
+ break;\r
+\r
+ //\r
+ // We will push the adjustment of these numeric values directly to the input handler\r
+ // NOTE: we won't handle manual input numeric\r
+ //\r
+ case '+':\r
+ case '-':\r
+ Statement = MenuOption->ThisTag;\r
+ if ((Statement->Operand == EFI_IFR_DATE_OP)\r
+ || (Statement->Operand == EFI_IFR_TIME_OP)\r
+ || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
+ ){\r
+ if (Key.UnicodeChar == '+') {\r
+ gDirection = SCAN_RIGHT;\r
+ } else {\r
+ gDirection = SCAN_LEFT;\r
+ }\r
+ Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Repaint to clear possible error prompt pop-up\r
+ //\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ }\r
+ if (OptionString != NULL) {\r
+ FreePool (OptionString);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case '^':\r
+ ScreenOperation = UiUp;\r
+ break;\r
+\r
+ case 'V':\r
+ case 'v':\r
+ ScreenOperation = UiDown;\r
+ break;\r
+\r
+ case ' ':\r
+ if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
+ if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+ ScreenOperation = UiSelect;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case CHAR_NULL:\r
+ if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
+ ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
+ ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
+ ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
+ ) {\r
+ //\r
+ // If the function key has been disabled, just ignore the 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
+ }\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CfScreenOperation:\r
+ if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
+ //\r
+ // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
+ // ignore the selection and go back to reading keys.\r
+ //\r
+ if (IsListEmpty (&Menu)) {\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 = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ if (IsSelectable (NextMenuOption)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Link == &Menu) {\r
+ ControlFlag = CfPrepareToReadKey;\r
+ break;\r
+ }\r
+ } else if (ScreenOperation == UiReset) {\r
+ //\r
+ // Press ESC to exit FormSet\r
+ //\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ Selection->Statement = NULL;\r
+ }\r
+\r
+ for (Index = 0;\r
+ Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
+ Index++\r
+ ) {\r
+ if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
+ ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case CfUiPrevious:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ if (IsListEmpty (&gMenuList)) {\r
+ Selection->Action = UI_ACTION_NONE;\r
+ if (IsListEmpty (&Menu)) {\r
+ ControlFlag = CfReadKey;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Remove the Cached page entry\r
+ //\r
+ UiRemoveMenuListEntry (Selection);\r
+\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ Selection->Statement = NULL;\r
+ break;\r
+\r
+ case CfUiSelect:\r
+ ControlFlag = CfCheckSelection;\r
+\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
+ break;\r
+ }\r
+\r
+ //\r
+ // Keep highlight on current MenuOption\r
+ //\r
+ Selection->QuestionId = Statement->QuestionId;\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
+ ControlFlag = CfUiReset;\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
+ ControlFlag = CfUiReset;\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
+ // 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 UiPrevious\r
+ //\r
+ UiAddMenuListEntry (Selection);\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
+ break;\r
+\r
+ case EFI_IFR_ACTION_OP:\r
+ //\r
+ // Process the Config string <ConfigResp>\r
+ //\r
+ Status = ProcessQuestionConfig (Selection, Statement);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // The action button may change some Question value, so refresh the form\r
+ //\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ break;\r
+\r
+ case EFI_IFR_RESET_BUTTON_OP:\r
+ //\r
+ // Reset Question to default value specified by DefaultId\r
+ //\r
+ ControlFlag = CfUiDefault;\r
+ DefaultId = Statement->DefaultId;\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
+ //\r
+ UpdateKeyHelp (MenuOption, TRUE);\r
+ Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ UpdateKeyHelp (MenuOption, FALSE);\r
+ } else {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ }\r
+\r
+ if (OptionString != NULL) {\r
+ FreePool (OptionString);\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CfUiReset:\r
+ //\r
+ // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+ //\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
+ //\r
+ // There is no parent menu for FrontPage\r
+ //\r
+ Selection->Action = UI_ACTION_NONE;\r
+ Selection->Statement = MenuOption->ThisTag;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // If NV flag is up, prompt user\r
+ //\r
+ if (gNvUpdateRequired) {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+ YesResponse = gYesResponse[0];\r
+ NoResponse = gNoResponse[0];\r
+\r
+ do {\r
+ CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, 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
+ //\r
+ // If the user hits the YesResponse key\r
+ //\r
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
+ } else {\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+\r
+ Selection->Action = UI_ACTION_NONE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+ UiFreeMenuList ();\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ return EFI_SUCCESS;\r
+\r
+ case CfUiLeft:\r
+ ControlFlag = CfCheckSelection;\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
+ NewPos = NewPos->BackLink;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case CfUiRight:\r
+ ControlFlag = CfCheckSelection;\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
+ NewPos = NewPos->ForwardLink;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case CfUiUp:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ SavedListEntry = TopOfScreen;\r
+\r
+ if (NewPos->BackLink != &Menu) {\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 != &Menu) {\r
+ NewPos = NewPos->BackLink;\r
+ }\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
+ }\r
+\r
+ Difference = MoveToNextStatement (TRUE, &NewPos);\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
+ }\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
+ //\r
+ if (SavedListEntry != Menu.ForwardLink) {\r
+ TopOfScreen = Menu.ForwardLink;\r
+ Repaint = TRUE;\r
+ }\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
+ } 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
+ break;\r
+\r
+ case CfUiPageUp:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ if (NewPos->BackLink == &Menu) {\r
+ NewLine = FALSE;\r
+ Repaint = FALSE;\r
+ break;\r
+ }\r
+\r
+ NewLine = TRUE;\r
+ Repaint = TRUE;\r
+ Link = TopOfScreen;\r
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ Index = BottomRow;\r
+ while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
+ Index = Index - PreviousMenuOption->Skip;\r
+ Link = Link->BackLink;\r
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ }\r
+\r
+ TopOfScreen = Link;\r
+ Difference = MoveToNextStatement (TRUE, &Link);\r
+ if (Difference > 0) {\r
+ //\r
+ // The focus MenuOption is above the TopOfScreen\r
+ //\r
+ TopOfScreen = Link;\r
+ } else if (Difference < 0) {\r
+ //\r
+ // This happens when there is no MenuOption can be focused from\r
+ // Current MenuOption to the first MenuOption\r
+ //\r
+ TopOfScreen = Menu.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
+ }\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 first page.\r
+ //\r
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+ AdjustDateAndTimePosition (TRUE, &NewPos);\r
+ break;\r
+\r
+ case CfUiPageDown:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ if (NewPos->ForwardLink == &Menu) {\r
+ NewLine = FALSE;\r
+ Repaint = FALSE;\r
+ break;\r
+ }\r
+\r
+ NewLine = TRUE;\r
+ Repaint = TRUE;\r
+ Link = TopOfScreen;\r
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ Index = TopRow;\r
+ while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {\r
+ Index = Index + NextMenuOption->Skip;\r
+ Link = Link->ForwardLink;\r
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+ }\r
+\r
+ Index += MoveToNextStatement (FALSE, &Link);\r
+ if (Index > BottomRow) {\r
+ //\r
+ // There are more MenuOption needing scrolling\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
+ //\r
+ NewLine = FALSE;\r
+ Repaint = FALSE;\r
+ } else {\r
+ NewPos = Link;\r
+ }\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
+ //\r
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+ AdjustDateAndTimePosition (TRUE, &NewPos);\r
+ break;\r
+\r
+ case CfUiDown:\r
+ ControlFlag = CfCheckSelection;\r
+ //\r
+ // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
+ // to be one that progresses to the next set of op-codes, we need to advance to the last\r
+ // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
+ // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
+ // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
+ // the Date/Time op-code.\r
+ //\r
+ SavedListEntry = NewPos;\r
+ DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos);\r
+\r
+ if (NewPos->ForwardLink != &Menu) {\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
+ //\r
+ // An option might be multi-line, so we need to reflect that data in the overall skip value\r
+ //\r
+ UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
+\r
+ Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
+ if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
+ (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+ NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
+ ) {\r
+ Temp ++;\r
+ }\r
+\r
+ //\r
+ // If we are going to scroll, update TopOfScreen\r
+ //\r
+ if (Temp > BottomRow) {\r
+ do {\r
+ //\r
+ // Is the current top of screen a zero-advance op-code?\r
+ // If so, keep moving forward till we hit a >0 advance op-code\r
+ //\r
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+\r
+ //\r
+ // If bottom op-code is more than one line or top op-code is more than one line\r
+ //\r
+ if ((DistanceValue > 1) || (MenuOption->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
+ //\r
+ // Skip the top op-code\r
+ //\r
+ TopOfScreen = TopOfScreen->ForwardLink;\r
+ Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
+\r
+ OldSkipValue = Difference;\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
+ //\r
+ // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
+ //\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
+ }\r
+ } else {\r
+ if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+ TopOfScreen = TopOfScreen->ForwardLink;\r
+ break;\r
+ } else {\r
+ SkipValue = OldSkipValue;\r
+ }\r
+ }\r
+ //\r
+ // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
+ // Let's set a skip flag to smoothly scroll the top of the screen.\r
+ //\r
+ if (SavedMenuOption->Skip > 1) {\r
+ if (SavedMenuOption == NextMenuOption) {\r
+ SkipValue = 0;\r
+ } else {\r
+ SkipValue++;\r
+ }\r
+ } else {\r
+ SkipValue = 0;\r
+ TopOfScreen = TopOfScreen->ForwardLink;\r
+ }\r
+ } while (SavedMenuOption->Skip == 0);\r
+\r
+ Repaint = TRUE;\r
+ OldSkipValue = SkipValue;\r
+ }\r
+\r
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+\r
+ UpdateStatusBar (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
+ // If we are at the end of the list and sitting on a text op, we need to more forward\r
+ //\r
+ ScreenOperation = UiUp;\r
+ ControlFlag = CfScreenOperation;\r
+ break;\r
+ }\r
+\r
+ MenuOption = SavedMenuOption;\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, &NewPos);\r
+ }\r
+ break;\r
+\r
+ case CfUiSave:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ //\r
+ // Submit the form\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
+\r
+ Repaint = TRUE;\r
+ NewLine = TRUE;\r
+ }\r
+ break;\r
+\r
+ case CfUiDefault:\r
+ ControlFlag = CfCheckSelection;\r
+\r
+ Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\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
+ }\r
+ break;\r
+\r
+ case CfUiNoOperation:\r
+ ControlFlag = CfCheckSelection;\r
+ break;\r
+\r
+ case CfExit:\r
+ UiFreeRefreshList ();\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\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
+\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+}\r