git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3788 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3159 lines
		
	
	
		
			100 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3159 lines
		
	
	
		
			100 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**@file
 | |
|   Implementation for UI.
 | |
| 
 | |
| Copyright (c) 2006 - 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "Setup.h"
 | |
| #include "Ui.h"
 | |
| #include "Colors.h"
 | |
| 
 | |
| //
 | |
| // Implementation
 | |
| //
 | |
| VOID
 | |
| SetUnicodeMem (
 | |
|   IN VOID   *Buffer,
 | |
|   IN UINTN  Size,
 | |
|   IN CHAR16 Value
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Set Buffer to Value for Size bytes.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer  - Memory to set.
 | |
| 
 | |
|   Size    - Number of bytes to set
 | |
| 
 | |
|   Value   - Value of the set operation.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR16  *Ptr;
 | |
| 
 | |
|   Ptr = Buffer;
 | |
|   while (Size--) {
 | |
|     *(Ptr++) = Value;
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiInitMenu (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Initialize Menu option list.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   InitializeListHead (&Menu);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiInitMenuList (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Initialize Menu option list.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   InitializeListHead (&gMenuList);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiRemoveMenuListEntry (
 | |
|   IN  UI_MENU_OPTION    *Selection,
 | |
|   OUT UI_MENU_OPTION    **PreviousSelection
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Remove Menu option list.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_LIST  *UiMenuList;
 | |
| 
 | |
|   *PreviousSelection = AllocateZeroPool (sizeof (UI_MENU_OPTION));
 | |
|   ASSERT (*PreviousSelection != NULL);
 | |
| 
 | |
|   if (!IsListEmpty (&gMenuList)) {
 | |
|     UiMenuList                      = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
 | |
|     (*PreviousSelection)->IfrNumber = UiMenuList->Selection.IfrNumber;
 | |
|     (*PreviousSelection)->FormId    = UiMenuList->Selection.FormId;
 | |
|     (*PreviousSelection)->Tags      = UiMenuList->Selection.Tags;
 | |
|     (*PreviousSelection)->ThisTag   = UiMenuList->Selection.ThisTag;
 | |
|     (*PreviousSelection)->Handle    = UiMenuList->Selection.Handle;
 | |
|     gEntryNumber                    = UiMenuList->FormerEntryNumber;
 | |
|     RemoveEntryList (&UiMenuList->MenuLink);
 | |
|     FreePool (UiMenuList);
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiFreeMenuList (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Free Menu option linked list.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_LIST  *UiMenuList;
 | |
| 
 | |
|   while (!IsListEmpty (&gMenuList)) {
 | |
|     UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
 | |
|     RemoveEntryList (&UiMenuList->MenuLink);
 | |
|     FreePool (UiMenuList);
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiAddMenuListEntry (
 | |
|   IN UI_MENU_OPTION   *Selection
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Add one menu entry to the linked lst
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_LIST  *UiMenuList;
 | |
| 
 | |
|   UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));
 | |
|   ASSERT (UiMenuList != NULL);
 | |
| 
 | |
|   UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;
 | |
|   CopyMem (&UiMenuList->Selection, Selection, sizeof (UI_MENU_OPTION));
 | |
| 
 | |
|   InsertHeadList (&gMenuList, &UiMenuList->MenuLink);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiFreeMenu (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Free Menu option linked list.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_OPTION  *MenuOption;
 | |
| 
 | |
|   while (!IsListEmpty (&Menu)) {
 | |
|     MenuOption = CR (Menu.ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|     RemoveEntryList (&MenuOption->Link);
 | |
| 
 | |
|     //
 | |
|     // We allocated space for this description when we did a GetToken, free it here
 | |
|     //
 | |
|     FreePool (MenuOption->Description);
 | |
|     FreePool (MenuOption);
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| UpdateDateAndTime (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Refresh screen with current date and/or time based on screen context
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR16              *OptionString;
 | |
|   MENU_REFRESH_ENTRY  *MenuRefreshEntry;
 | |
|   UINTN               Index;
 | |
|   UINTN               Loop;
 | |
| 
 | |
|   OptionString = NULL;
 | |
| 
 | |
|   if (gMenuRefreshHead != NULL) {
 | |
| 
 | |
|     MenuRefreshEntry = gMenuRefreshHead;
 | |
| 
 | |
|     do {
 | |
|       gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);
 | |
|       ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &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);
 | |
|       }
 | |
| 
 | |
|       MenuRefreshEntry = MenuRefreshEntry->Next;
 | |
| 
 | |
|     } while (MenuRefreshEntry != NULL);
 | |
|   }
 | |
| 
 | |
|   if (OptionString != NULL) {
 | |
|     FreePool (OptionString);
 | |
|   }
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| UiWaitForSingleEvent (
 | |
|   IN EFI_EVENT                Event,
 | |
|   IN UINT64                   Timeout OPTIONAL
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Wait for a given event to fire, or for an optional timeout to expire.
 | |
| 
 | |
| Arguments:
 | |
|   Event            - The event to wait for
 | |
| 
 | |
|   Timeout          - An optional timeout value in 100 ns units.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS      - Event fired before Timeout expired.
 | |
|   EFI_TIME_OUT     - Timout expired before Event fired.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   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
 | |
|     //
 | |
|     Timeout = 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;
 | |
|         UpdateDateAndTime ();
 | |
|       }
 | |
| 
 | |
|       gBS->CloseEvent (TimerEvent);
 | |
|     } while (Status == EFI_TIMEOUT);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiAddMenuOption (
 | |
|   IN CHAR16         *String,
 | |
|   IN EFI_HII_HANDLE Handle,
 | |
|   IN EFI_TAG        *Tags,
 | |
|   IN VOID           *FormBinary,
 | |
|   IN UINTN          IfrNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Add one menu option by specified description and context.
 | |
| 
 | |
| Arguments:
 | |
|   String - String description for this option.
 | |
|   Context - Context data for entry.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_OPTION  *MenuOption;
 | |
| 
 | |
|   MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
 | |
|   ASSERT (MenuOption);
 | |
| 
 | |
|   MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;
 | |
|   MenuOption->Description = String;
 | |
|   MenuOption->Handle      = Handle;
 | |
|   MenuOption->FormBinary  = FormBinary;
 | |
|   MenuOption->IfrNumber   = IfrNumber;
 | |
|   MenuOption->Skip        = 1;
 | |
|   MenuOption->Tags        = Tags;
 | |
|   MenuOption->TagIndex    = 0;
 | |
|   MenuOption->ThisTag     = &(MenuOption->Tags[MenuOption->TagIndex]);
 | |
|   MenuOption->EntryNumber = (UINT16) IfrNumber;
 | |
| 
 | |
|   InsertTailList (&Menu, &MenuOption->Link);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UiAddSubMenuOption (
 | |
|   IN CHAR16           *String,
 | |
|   IN EFI_HII_HANDLE   Handle,
 | |
|   IN EFI_TAG          *Tags,
 | |
|   IN UINTN            TagIndex,
 | |
|   IN UINT16           FormId,
 | |
|   IN UINT16           MenuItemCount
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Add one menu option by specified description and context.
 | |
| 
 | |
| Arguments:
 | |
|   String - String description for this option.
 | |
|   Context - Context data for entry.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UI_MENU_OPTION  *MenuOption;
 | |
| 
 | |
|   MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
 | |
|   ASSERT (MenuOption);
 | |
| 
 | |
|   MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;
 | |
|   MenuOption->Description = String;
 | |
|   MenuOption->Handle      = Handle;
 | |
|   MenuOption->Skip        = Tags[TagIndex].NumberOfLines;
 | |
|   MenuOption->IfrNumber   = gActiveIfr;
 | |
|   MenuOption->Tags        = Tags;
 | |
|   MenuOption->TagIndex    = TagIndex;
 | |
|   MenuOption->ThisTag     = &(MenuOption->Tags[MenuOption->TagIndex]);
 | |
|   MenuOption->Consistency = Tags[TagIndex].Consistency;
 | |
|   MenuOption->FormId      = FormId;
 | |
|   MenuOption->GrayOut     = Tags[TagIndex].GrayOut;
 | |
|   MenuOption->EntryNumber = MenuItemCount;
 | |
| 
 | |
|   InsertTailList (&Menu, &MenuOption->Link);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| CreateDialog (
 | |
|   IN  UINTN                       NumberOfLines,
 | |
|   IN  BOOLEAN                     HotKey,
 | |
|   IN  UINTN                       MaximumStringSize,
 | |
|   OUT CHAR16                      *StringBuffer,
 | |
|   OUT EFI_INPUT_KEY               *KeyValue,
 | |
|   IN  CHAR16                      *String,
 | |
|   ...
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Routine used to abstract a generic dialog interface and return the selected key or string
 | |
| 
 | |
| Arguments:
 | |
|   NumberOfLines -     The number of lines for the dialog box
 | |
|   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
 | |
|   MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
 | |
|   StringBuffer -      The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
 | |
|   KeyValue -          The EFI_KEY value returned if HotKey is TRUE..
 | |
|   String -            Pointer to the first string in the list
 | |
|   ... -               A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
 | |
| 
 | |
| Returns:
 | |
|   EFI_SUCCESS -           Displayed dialog and received user interaction
 | |
|   EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
 | |
|   EFI_DEVICE_ERROR -      User typed in an ESC character to exit the routine
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   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;
 | |
|   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 (LargestString == 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) {
 | |
|     WaitForKeyStroke (&Key);
 | |
|     CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
 | |
| 
 | |
|   } else {
 | |
|     do {
 | |
|       WaitForKeyStroke (&Key);
 | |
| 
 | |
|       switch (Key.UnicodeChar) {
 | |
|       case CHAR_NULL:
 | |
|         switch (Key.ScanCode) {
 | |
|         case SCAN_ESC:
 | |
|           FreePool (TempString);
 | |
|           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;
 | |
|         FreePool (TempString);
 | |
|         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 = (CHAR16) BOXDRAW_DOWN_RIGHT;
 | |
|   PrintCharAt (Start, Top, Character);
 | |
|   Character = (CHAR16) BOXDRAW_HORIZONTAL;
 | |
|   for (Index = Start; Index + 2 < End; Index++) {
 | |
|     PrintChar (Character);
 | |
|   }
 | |
| 
 | |
|   Character = (CHAR16) BOXDRAW_DOWN_LEFT;
 | |
|   PrintChar (Character);
 | |
|   Character = (CHAR16) 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 = (CHAR16) BOXDRAW_UP_RIGHT;
 | |
|   PrintCharAt (Start, Bottom - 1, Character);
 | |
|   Character = (CHAR16) BOXDRAW_HORIZONTAL;
 | |
|   for (Index = Start; Index + 2 < End; Index++) {
 | |
|     PrintChar (Character);
 | |
|   }
 | |
| 
 | |
|   Character = (CHAR16) BOXDRAW_UP_LEFT;
 | |
|   PrintChar (Character);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| CreatePopUp (
 | |
|   IN  UINTN                       RequestedWidth,
 | |
|   IN  UINTN                       NumberOfLines,
 | |
|   IN  CHAR16                      *ArrayOfStrings,
 | |
|   ...
 | |
|   )
 | |
| {
 | |
|   CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);
 | |
| }
 | |
| 
 | |
| 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, (CHAR16 *) 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,
 | |
|             (CHAR16 *) 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;
 | |
|   }
 | |
| 
 | |
|   FreePool (InputErrorMessage);
 | |
|   FreePool (NvUpdateMessage);
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| FreeData (
 | |
|   IN EFI_FILE_FORM_TAGS           *FileFormTagsHead,
 | |
|   IN CHAR16                       *FormattedString,
 | |
|   IN CHAR16                       *OptionString
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Used to remove the allocated data instances
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FILE_FORM_TAGS      *FileForm;
 | |
|   EFI_FILE_FORM_TAGS      *PreviousFileForm;
 | |
|   EFI_FORM_TAGS           *FormTags;
 | |
|   EFI_FORM_TAGS           *PreviousFormTags;
 | |
|   EFI_IFR_BINARY          *IfrBinary;
 | |
|   EFI_IFR_BINARY          *PreviousIfrBinary;
 | |
|   EFI_INCONSISTENCY_DATA  *Inconsistent;
 | |
|   EFI_VARIABLE_DEFINITION *VariableDefinition;
 | |
|   EFI_VARIABLE_DEFINITION *PreviousVariableDefinition;
 | |
|   VOID                    *Buffer;
 | |
|   UINTN                   Index;
 | |
| 
 | |
|   FileForm = FileFormTagsHead;
 | |
| 
 | |
|   if (FormattedString != NULL) {
 | |
|     FreePool (FormattedString);
 | |
|   }
 | |
| 
 | |
|   if (OptionString != NULL) {
 | |
|     FreePool (OptionString);
 | |
|   }
 | |
| 
 | |
|   for (; FileForm != NULL;) {
 | |
|     PreviousFileForm = NULL;
 | |
| 
 | |
|     //
 | |
|     // Advance FileForm to the last entry
 | |
|     //
 | |
|     for (; FileForm->NextFile != NULL; FileForm = FileForm->NextFile) {
 | |
|       PreviousFileForm = FileForm;
 | |
|     }
 | |
| 
 | |
|     FormTags = &FileForm->FormTags;
 | |
| 
 | |
|     for (; FormTags != NULL;) {
 | |
|       FormTags          = &FileForm->FormTags;
 | |
|       PreviousFormTags  = NULL;
 | |
| 
 | |
|       //
 | |
|       // Advance FormTags to the last entry
 | |
|       //
 | |
|       for (; FormTags->Next != NULL; FormTags = FormTags->Next) {
 | |
|         PreviousFormTags = FormTags;
 | |
|       }
 | |
|       //
 | |
|       // Walk through each of the tags and free the IntList allocation
 | |
|       //
 | |
|       for (Index = 0; FormTags->Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {
 | |
|         //
 | |
|         // It is more than likely that the very last page will contain an end formset
 | |
|         //
 | |
|         if (FormTags->Tags[Index].Operand == EFI_IFR_END_FORM_SET_OP) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (FormTags->Tags[Index].IntList != NULL) {
 | |
|           FreePool (FormTags->Tags[Index].IntList);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (PreviousFormTags != NULL) {
 | |
|         FreePool (FormTags->Tags);
 | |
|         FormTags = PreviousFormTags;
 | |
|         FreePool (FormTags->Next);
 | |
|         FormTags->Next = NULL;
 | |
|       } else {
 | |
|         FreePool (FormTags->Tags);
 | |
|         FormTags = NULL;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Last FileForm entry's Inconsistent database
 | |
|     //
 | |
|     Inconsistent = FileForm->InconsistentTags;
 | |
| 
 | |
|     //
 | |
|     // Advance Inconsistent to the last entry
 | |
|     //
 | |
|     for (; Inconsistent->Next != NULL; Inconsistent = Inconsistent->Next)
 | |
|       ;
 | |
| 
 | |
|     for (; Inconsistent != NULL;) {
 | |
|       //
 | |
|       // Preserve the Previous pointer
 | |
|       //
 | |
|       Buffer = (VOID *) Inconsistent->Previous;
 | |
| 
 | |
|       //
 | |
|       // Free the current entry
 | |
|       //
 | |
|       FreePool (Inconsistent);
 | |
| 
 | |
|       //
 | |
|       // Restore the Previous pointer
 | |
|       //
 | |
|       Inconsistent = (EFI_INCONSISTENCY_DATA *) Buffer;
 | |
|     }
 | |
| 
 | |
|     VariableDefinition = FileForm->VariableDefinitions;
 | |
| 
 | |
|     for (; VariableDefinition != NULL;) {
 | |
|       VariableDefinition          = FileForm->VariableDefinitions;
 | |
|       PreviousVariableDefinition  = NULL;
 | |
| 
 | |
|       //
 | |
|       // Advance VariableDefinitions to the last entry
 | |
|       //
 | |
|       for (; VariableDefinition->Next != NULL; VariableDefinition = VariableDefinition->Next) {
 | |
|         PreviousVariableDefinition = VariableDefinition;
 | |
|       }
 | |
| 
 | |
|       FreePool (VariableDefinition->VariableName);
 | |
| 
 | |
|       if (VariableDefinition->NvRamMap != NULL) {
 | |
|         FreePool (VariableDefinition->NvRamMap);
 | |
|       }
 | |
| 
 | |
|       if (VariableDefinition->FakeNvRamMap != NULL) {
 | |
|         FreePool (VariableDefinition->FakeNvRamMap);
 | |
|       }
 | |
| 
 | |
|       if (PreviousVariableDefinition != NULL) {
 | |
|         VariableDefinition = PreviousVariableDefinition;
 | |
|         FreePool (VariableDefinition->Next);
 | |
|         VariableDefinition->Next = NULL;
 | |
|       } else {
 | |
|         FreePool (VariableDefinition);
 | |
|         VariableDefinition = NULL;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (PreviousFileForm != NULL) {
 | |
|       FileForm = PreviousFileForm;
 | |
|       FreePool (FileForm->NextFile);
 | |
|       FileForm->NextFile = NULL;
 | |
|     } else {
 | |
|       FreePool (FileForm);
 | |
|       FileForm = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IfrBinary = gBinaryDataHead;
 | |
| 
 | |
|   for (; IfrBinary != NULL;) {
 | |
|     IfrBinary         = gBinaryDataHead;
 | |
|     PreviousIfrBinary = NULL;
 | |
| 
 | |
|     //
 | |
|     // Advance IfrBinary to the last entry
 | |
|     //
 | |
|     for (; IfrBinary->Next != NULL; IfrBinary = IfrBinary->Next) {
 | |
|       PreviousIfrBinary = IfrBinary;
 | |
|     }
 | |
| 
 | |
|     FreePool (IfrBinary->IfrPackage);
 | |
| 
 | |
|     if (PreviousIfrBinary != NULL) {
 | |
|       IfrBinary = PreviousIfrBinary;
 | |
|       FreePool (IfrBinary->Next);
 | |
|       IfrBinary->Next = NULL;
 | |
|     } else {
 | |
|       FreePool (IfrBinary);
 | |
|       IfrBinary = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (gPreviousValue);
 | |
|   gPreviousValue = NULL;
 | |
| 
 | |
|   //
 | |
|   // Free Browser Strings
 | |
|   //
 | |
|   FreePool (gPressEnter);
 | |
|   FreePool (gConfirmError);
 | |
|   FreePool (gConfirmPassword);
 | |
|   FreePool (gPromptForNewPassword);
 | |
|   FreePool (gPromptForPassword);
 | |
|   FreePool (gToggleCheckBox);
 | |
|   FreePool (gNumericInput);
 | |
|   FreePool (gMakeSelection);
 | |
|   FreePool (gMoveHighlight);
 | |
|   FreePool (gEscapeString);
 | |
|   FreePool (gEnterCommitString);
 | |
|   FreePool (gEnterString);
 | |
|   FreePool (gFunctionOneString);
 | |
|   FreePool (gFunctionTwoString);
 | |
|   FreePool (gFunctionNineString);
 | |
|   FreePool (gFunctionTenString);
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| BOOLEAN
 | |
| SelectionsAreValid (
 | |
|   IN  UI_MENU_OPTION               *MenuOption,
 | |
|   IN  EFI_FILE_FORM_TAGS           *FileFormTagsHead
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Initiate late consistency checks against the current page.
 | |
| 
 | |
| Arguments:
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   EFI_TAG                 *Tag;
 | |
|   EFI_FILE_FORM_TAGS      *FileFormTags;
 | |
|   CHAR16                  *StringPtr;
 | |
|   CHAR16                  NullCharacter;
 | |
|   UINTN                   Index;
 | |
|   UINT16                  *NvRamMap;
 | |
|   STRING_REF              PopUp;
 | |
|   EFI_INPUT_KEY           Key;
 | |
|   EFI_VARIABLE_DEFINITION *VariableDefinition;
 | |
| 
 | |
|   StringPtr     = (CHAR16 *) L"\0";
 | |
|   NullCharacter = CHAR_NULL;
 | |
| 
 | |
|   FileFormTags  = FileFormTagsHead;
 | |
| 
 | |
|   for (Index = 0; Index < MenuOption->IfrNumber; Index++) {
 | |
|     FileFormTags = FileFormTags->NextFile;
 | |
|   }
 | |
| 
 | |
|   for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {
 | |
|     MenuOption  = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|     Tag         = MenuOption->ThisTag;
 | |
| 
 | |
|     ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);
 | |
|     NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];
 | |
| 
 | |
|     //
 | |
|     // If the op-code has a late check, ensure consistency checks are now applied
 | |
|     //
 | |
|     if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {
 | |
|       if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {
 | |
|         if (PopUp != 0x0000) {
 | |
|           StringPtr = GetToken (PopUp, MenuOption->Handle);
 | |
| 
 | |
|           CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);
 | |
| 
 | |
|           do {
 | |
|             WaitForKeyStroke (&Key);
 | |
| 
 | |
|             switch (Key.UnicodeChar) {
 | |
| 
 | |
|             case CHAR_CARRIAGE_RETURN:
 | |
|               //
 | |
|               // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
 | |
|               //
 | |
|               CopyMem (NvRamMap, &Tag->OldValue, Tag->StorageWidth);
 | |
|               FreePool (StringPtr);
 | |
|               break;
 | |
| 
 | |
|             default:
 | |
|               break;
 | |
|             }
 | |
|           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
|         }
 | |
| 
 | |
|         return FALSE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| UINT16
 | |
| GetWidth (
 | |
|   IN EFI_TAG                        *Tag,
 | |
|   IN EFI_HII_HANDLE                 Handle
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Get the supported width for a particular op-code
 | |
| 
 | |
| Arguments:
 | |
|   Tag - The Tag structure passed in.
 | |
|   Handle - The handle in the HII database being used
 | |
| 
 | |
| Returns:
 | |
|   Returns the number of CHAR16 characters that is support.
 | |
| 
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR16  *String;
 | |
|   UINTN   Size;
 | |
| 
 | |
|   Size = 0x00;
 | |
| 
 | |
|   //
 | |
|   // See if the second text parameter is really NULL
 | |
|   //
 | |
|   if ((Tag->Operand == EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) {
 | |
|     String  = GetToken (Tag->TextTwo, Handle);
 | |
|     Size    = StrLen (String);
 | |
|     FreePool (String);
 | |
|   }
 | |
| 
 | |
|   if ((Tag->Operand == EFI_IFR_SUBTITLE_OP) ||
 | |
|       (Tag->Operand == EFI_IFR_REF_OP) ||
 | |
|       (Tag->Operand == EFI_IFR_PASSWORD_OP) ||
 | |
|       (Tag->Operand == EFI_IFR_STRING_OP) ||
 | |
|       (Tag->Operand == EFI_IFR_INVENTORY_OP) ||
 | |
|       //
 | |
|       // Allow a wide display if text op-code and no secondary text op-code
 | |
|       //
 | |
|       ((Tag->Operand == EFI_IFR_TEXT_OP) && (Size == 0x0000))
 | |
|       ) {
 | |
|     return (UINT16) (gPromptBlockWidth + gOptionBlockWidth);
 | |
|   } else {
 | |
|     return (UINT16) gPromptBlockWidth;
 | |
|   }
 | |
| }
 | |
| 
 | |
| UINT16
 | |
| GetLineByWidth (
 | |
|   IN      CHAR16                      *InputString,
 | |
|   IN      UINT16                      LineWidth,
 | |
|   IN OUT  UINTN                       *Index,
 | |
|   OUT     CHAR16                      **OutputString
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   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.
 | |
| 
 | |
| Arguments:
 | |
|   InputString - String description for this option.
 | |
|   LineWidth - Width of the desired string to extract in CHAR16 characters
 | |
|   Index - Where in InputString to start the copy process
 | |
|   OutputString - Buffer to copy the string into
 | |
| 
 | |
| Returns:
 | |
|   Returns the number of CHAR16 characters that were copied into the OutputString buffer.
 | |
| 
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| UpdateOptionSkipLines (
 | |
|   IN EFI_IFR_DATA_ARRAY           *PageData,
 | |
|   IN UI_MENU_OPTION               *MenuOption,
 | |
|   IN EFI_FILE_FORM_TAGS           *FileFormTagsHead,
 | |
|   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 (MenuOption, FALSE, FileFormTagsHead, PageData, &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++;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       FreePool (OutputString);
 | |
|       if (SkipValue != 0) {
 | |
|         SkipValue--;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Row = OriginalRow;
 | |
|   }
 | |
| 
 | |
|   *OptionalString = OptionString;
 | |
| }
 | |
| //
 | |
| // 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 }
 | |
| };
 | |
| 
 | |
| UI_MENU_OPTION *
 | |
| UiDisplayMenu (
 | |
|   IN  BOOLEAN                      SubMenu,
 | |
|   IN  EFI_FILE_FORM_TAGS           *FileFormTagsHead,
 | |
|   OUT EFI_IFR_DATA_ARRAY           *PageData
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   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.
 | |
| 
 | |
| Arguments:
 | |
|   SubMenu          - Indicate is sub menu.
 | |
|   FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
 | |
|   PageData         - A pointer to the EFI_IFR_DATA_ARRAY.
 | |
| 
 | |
| Returns:
 | |
|   Return the pointer of the menu which selected,
 | |
|   otherwise return NULL.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INTN                        SkipValue;
 | |
|   INTN                        Difference;
 | |
|   INTN                        OldSkipValue;
 | |
|   UINTN                       Row;
 | |
|   UINTN                       Col;
 | |
|   UINTN                       Temp;
 | |
|   UINTN                       Temp2;
 | |
|   UINTN                       TopRow;
 | |
|   UINTN                       BottomRow;
 | |
|   UINTN                       OriginalRow;
 | |
|   UINTN                       Index;
 | |
|   UINTN                       DataAndTimeLineNumberPad;
 | |
|   UINT32                      Count;
 | |
|   INT16                       OriginalTimeOut;
 | |
|   UINT8                       *Location;
 | |
|   UINT16                      Width;
 | |
|   CHAR16                      *StringPtr;
 | |
|   CHAR16                      *OptionString;
 | |
|   CHAR16                      *OutputString;
 | |
|   CHAR16                      *FormattedString;
 | |
|   CHAR16                      YesResponse;
 | |
|   CHAR16                      NoResponse;
 | |
|   BOOLEAN                     NewLine;
 | |
|   BOOLEAN                     Repaint;
 | |
|   BOOLEAN                     SavedValue;
 | |
|   EFI_STATUS                  Status;
 | |
|   UI_MENU_LIST                *UiMenuList;
 | |
|   EFI_INPUT_KEY               Key;
 | |
|   LIST_ENTRY                  *Link;
 | |
|   LIST_ENTRY                  *NewPos;
 | |
|   LIST_ENTRY                  *TopOfScreen;
 | |
|   LIST_ENTRY                  *SavedListEntry;
 | |
|   UI_MENU_OPTION              *Selection;
 | |
|   UI_MENU_OPTION              *MenuOption;
 | |
|   UI_MENU_OPTION              *NextMenuOption;
 | |
|   UI_MENU_OPTION              *SavedMenuOption;
 | |
|   UI_MENU_OPTION              *PreviousMenuOption;
 | |
|   EFI_IFR_BINARY              *IfrBinary;
 | |
|   UI_CONTROL_FLAG             ControlFlag;
 | |
|   EFI_SCREEN_DESCRIPTOR       LocalScreen;
 | |
|   EFI_FILE_FORM_TAGS          *FileFormTags;
 | |
|   MENU_REFRESH_ENTRY          *MenuRefreshEntry;
 | |
|   MENU_REFRESH_ENTRY          *OldMenuRefreshEntry;
 | |
|   UI_SCREEN_OPERATION         ScreenOperation;
 | |
|   EFI_VARIABLE_DEFINITION     *VariableDefinition;
 | |
|   EFI_VARIABLE_DEFINITION     *UiDefaultVarDef; // Only used in CfUiDefault State
 | |
|   EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;
 | |
|   EFI_HII_VARIABLE_PACK_LIST  *NvMapListHead;
 | |
|   EFI_HII_VARIABLE_PACK_LIST  *NvMapListNode;
 | |
|   VOID                        *NvMap;
 | |
|   UINTN                       NvMapSize;
 | |
| 
 | |
|   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
| 
 | |
|   VariableDefinition  = NULL;
 | |
|   Status              = EFI_SUCCESS;
 | |
|   FormattedString     = NULL;
 | |
|   OptionString        = NULL;
 | |
|   ScreenOperation     = UiNoOperation;
 | |
|   NewLine             = TRUE;
 | |
|   FormCallback        = NULL;
 | |
|   FileFormTags        = NULL;
 | |
|   OutputString        = NULL;
 | |
|   gUpArrow            = FALSE;
 | |
|   gDownArrow          = FALSE;
 | |
|   SkipValue           = 0;
 | |
|   OldSkipValue        = 0;
 | |
|   MenuRefreshEntry    = gMenuRefreshHead;
 | |
|   OldMenuRefreshEntry = gMenuRefreshHead;
 | |
|   NextMenuOption      = NULL;
 | |
|   PreviousMenuOption  = NULL;
 | |
|   SavedMenuOption     = NULL;
 | |
|   IfrBinary           = NULL;
 | |
|   NvMap               = NULL;
 | |
|   NvMapSize           = 0;
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   if (SubMenu) {
 | |
|     Col = LocalScreen.LeftColumn;
 | |
|   } else {
 | |
|     Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;
 | |
|   }
 | |
| 
 | |
|   BottomRow   = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;
 | |
| 
 | |
|   TopOfScreen = Menu.ForwardLink;
 | |
|   Repaint     = TRUE;
 | |
|   MenuOption  = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get user's selection
 | |
|   //
 | |
|   Selection = NULL;
 | |
|   NewPos    = Menu.ForwardLink;
 | |
|   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
 | |
| 
 | |
|   UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);
 | |
| 
 | |
|   ControlFlag = CfInitialization;
 | |
| 
 | |
|   while (TRUE) {
 | |
|     switch (ControlFlag) {
 | |
|     case CfInitialization:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       if (gExitRequired) {
 | |
|         ScreenOperation = UiReset;
 | |
|         ControlFlag     = CfScreenOperation;
 | |
|       } else if (gSaveRequired) {
 | |
|         ScreenOperation = UiSave;
 | |
|         ControlFlag     = CfScreenOperation;
 | |
|       } else if (IsListEmpty (&Menu)) {
 | |
|         ControlFlag = CfReadKey;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfCheckSelection:
 | |
|       if (Selection != NULL) {
 | |
|         ControlFlag = CfExit;
 | |
|       } else {
 | |
|         ControlFlag = CfRepaint;
 | |
|       }
 | |
| 
 | |
|       FileFormTags = FileFormTagsHead;
 | |
|       break;
 | |
| 
 | |
|     case CfRepaint:
 | |
|       ControlFlag = CfRefreshHighLight;
 | |
| 
 | |
|       if (Repaint) {
 | |
|         //
 | |
|         // Display menu
 | |
|         //
 | |
|         SavedMenuOption = MenuOption;
 | |
|         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
 | |
|           );
 | |
| 
 | |
|         while (gMenuRefreshHead != NULL) {
 | |
|           OldMenuRefreshEntry = gMenuRefreshHead->Next;
 | |
| 
 | |
|           FreePool (gMenuRefreshHead);
 | |
| 
 | |
|           gMenuRefreshHead = OldMenuRefreshEntry;
 | |
|         }
 | |
| 
 | |
|         for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {
 | |
|           MenuOption          = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           MenuOption->Row     = Row;
 | |
|           OriginalRow         = Row;
 | |
|           MenuOption->Col     = Col;
 | |
|           MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
 | |
| 
 | |
|           if (SubMenu) {
 | |
|             if (MenuOption->ThisTag->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);
 | |
|               }
 | |
|             }
 | |
| 
 | |
|             Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
 | |
| 
 | |
|             OriginalRow = Row;
 | |
| 
 | |
|             for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
 | |
|               if ((Temp == 0) && (Row <= BottomRow)) {
 | |
|                 PrintStringAt (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++;
 | |
|                 }
 | |
|               }
 | |
| 
 | |
|               FreePool (OutputString);
 | |
|               if (Temp != 0) {
 | |
|                 Temp--;
 | |
|               }
 | |
|             }
 | |
| 
 | |
|             Temp  = 0;
 | |
| 
 | |
|             Row   = OriginalRow;
 | |
| 
 | |
|             gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
 | |
|             ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
 | |
| 
 | |
|             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++) {
 | |
|                   MenuOption->OptCol++;
 | |
|                 }
 | |
| 
 | |
|                 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
 | |
|                   OptionString[Count] = OptionString[Index];
 | |
|                   Count++;
 | |
|                 }
 | |
| 
 | |
|                 OptionString[Count] = CHAR_NULL;
 | |
|               }
 | |
| 
 | |
|               //
 | |
|               // If this is a date or time op-code and is used to reflect an RTC, register the op-code
 | |
|               //
 | |
|                 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
 | |
|                      MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) &&
 | |
|                     (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {
 | |
| 
 | |
|                 if (gMenuRefreshHead == NULL) {
 | |
|                   MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
 | |
|                   ASSERT (MenuRefreshEntry != NULL);
 | |
|                   MenuRefreshEntry->MenuOption        = MenuOption;
 | |
|                   MenuRefreshEntry->FileFormTagsHead  = FileFormTagsHead;
 | |
|                   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->FileFormTagsHead  = FileFormTagsHead;
 | |
|                   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++;
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
| 
 | |
|                 FreePool (OutputString);
 | |
|                 if (Temp2 != 0) {
 | |
|                   Temp2--;
 | |
|                 }
 | |
|               }
 | |
| 
 | |
|               Temp2 = 0;
 | |
|               Row   = OriginalRow;
 | |
|             }
 | |
|             //
 | |
|             // If this is a text op with secondary text information
 | |
|             //
 | |
|             if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {
 | |
|               StringPtr   = GetToken (MenuOption->ThisTag->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++;
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
| 
 | |
|                 FreePool (OutputString);
 | |
|                 if (Temp2 != 0) {
 | |
|                   Temp2--;
 | |
|                 }
 | |
|               }
 | |
| 
 | |
|               Row = OriginalRow;
 | |
|               FreePool (StringPtr);
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // For now, assume left-justified 72 width max setup entries
 | |
|             //
 | |
|             PrintStringAt (Col, Row, MenuOption->Description);
 | |
|           }
 | |
|           //
 | |
|           // Tracker 6210 - 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,
 | |
|             (CHAR16 *) 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,
 | |
|             (CHAR16 *) L"%c",
 | |
|             ARROW_DOWN
 | |
|             );
 | |
|           gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
 | |
|         }
 | |
| 
 | |
|         if (SavedMenuOption != NULL) {
 | |
|           MenuOption = SavedMenuOption;
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfRefreshHighLight:
 | |
|       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 (NewPos != NULL) {
 | |
|         gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
 | |
|         if (SubMenu) {
 | |
|           if (gLastOpr && (gEntryNumber != -1)) {
 | |
|             MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|             if (gEntryNumber != MenuOption->EntryNumber) {
 | |
|               ScreenOperation = UiDown;
 | |
|               ControlFlag     = CfScreenOperation;
 | |
|               break;
 | |
|             } else {
 | |
|               gLastOpr = FALSE;
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &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++;
 | |
|               }
 | |
| 
 | |
|               FreePool (OutputString);
 | |
|             }
 | |
| 
 | |
|             MenuOption->Row = OriginalRow;
 | |
|           } else {
 | |
|             if (NewLine) {
 | |
|               if (MenuOption->ThisTag->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 (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++;
 | |
|                 }
 | |
| 
 | |
|                 FreePool (OutputString);
 | |
|               }
 | |
| 
 | |
|               MenuOption->Row = OriginalRow;
 | |
|               gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
 | |
|           gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
 | |
|         }
 | |
| 
 | |
|         MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|         if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {
 | |
|           ScreenOperation = UiDown;
 | |
|           ControlFlag     = CfScreenOperation;
 | |
|           break;
 | |
|         } else {
 | |
|           gPriorMenuEntry = 0;
 | |
|         }
 | |
|         //
 | |
|         // 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
 | |
|         //
 | |
|         if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
 | |
|           //
 | |
|           // If we previously hit an UP command and we are still sitting on a text operation
 | |
|           // we must continue going up
 | |
|           //
 | |
|           if (ScreenOperation == UiUp) {
 | |
|             ControlFlag = CfScreenOperation;
 | |
|             break;
 | |
|           } else {
 | |
|             ScreenOperation = UiDown;
 | |
|             ControlFlag     = CfScreenOperation;
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|         //
 | |
|         // 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;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (SubMenu) {
 | |
|           ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);
 | |
|           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++;
 | |
|               }
 | |
| 
 | |
|               FreePool (OutputString);
 | |
|             }
 | |
| 
 | |
|             MenuOption->Row = OriginalRow;
 | |
|           } else {
 | |
|             if (NewLine) {
 | |
|               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 (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++;
 | |
|                 }
 | |
| 
 | |
|                 FreePool (OutputString);
 | |
|               }
 | |
| 
 | |
|               MenuOption->Row = OriginalRow;
 | |
| 
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||
 | |
|               ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||
 | |
|               (ScreenOperation == UiNoOperation)
 | |
|               ) {
 | |
|             UpdateKeyHelp (MenuOption, FALSE);
 | |
|           }
 | |
|         } else {
 | |
|           gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
 | |
|         }
 | |
|         //
 | |
|         // 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 (SubMenu &&
 | |
|             (Repaint || NewLine ||
 | |
|              (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
 | |
|              (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) &&
 | |
|             !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {
 | |
|         //
 | |
|         // Don't print anything if it is a NULL help token
 | |
|         //
 | |
|         if (MenuOption->ThisTag->Help == 0x00000000) {
 | |
|           StringPtr = (CHAR16 *) 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], (CHAR16 *) 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;
 | |
| 
 | |
|       for (Index = 0; Index < MenuOption->IfrNumber; Index++) {
 | |
|         FileFormTags = FileFormTags->NextFile;
 | |
|       }
 | |
| 
 | |
|       ScreenOperation = UiNoOperation;
 | |
| 
 | |
|       Status = gBS->HandleProtocol (
 | |
|                       (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,
 | |
|                       &gEfiFormCallbackProtocolGuid,
 | |
|                       (VOID **) &FormCallback
 | |
|                       );
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case CfReadKey:
 | |
|       ControlFlag     = CfScreenOperation;
 | |
| 
 | |
|       OriginalTimeOut = FrontPageTimeOutValue;
 | |
|       do {
 | |
|         if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {
 | |
|           //
 | |
|           // Remember that if set to 0, must immediately boot an option
 | |
|           //
 | |
|           if (FrontPageTimeOutValue == 0) {
 | |
|             FrontPageTimeOutValue = 0xFFFF;
 | |
|             Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               Status = EFI_TIMEOUT;
 | |
|             }
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
 | |
|           if (Status == EFI_TIMEOUT) {
 | |
|             EFI_IFR_DATA_ENTRY *DataEntry;
 | |
| 
 | |
|             DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);
 | |
| 
 | |
|             PageData->EntryCount  = 1;
 | |
|             Count                 = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);
 | |
|             CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));
 | |
| 
 | |
|             if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
 | |
|               FormCallback->Callback (
 | |
|                               FormCallback,
 | |
|                               0xFFFF,
 | |
|                               (EFI_IFR_DATA_ARRAY *) PageData,
 | |
|                               NULL
 | |
|                               );
 | |
|             }
 | |
|             //
 | |
|             // Count down 1 second
 | |
|             //
 | |
|             FrontPageTimeOutValue--;
 | |
| 
 | |
|           } else {
 | |
|             ASSERT (!EFI_ERROR (Status));
 | |
|             PageData->EntryCount = 0;
 | |
|             if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
 | |
|               FormCallback->Callback (
 | |
|                               FormCallback,
 | |
|                               0xFFFE,
 | |
|                               (EFI_IFR_DATA_ARRAY *) PageData,
 | |
|                               NULL
 | |
|                               );
 | |
|             }
 | |
| 
 | |
|             FrontPageTimeOutValue = 0xFFFF;
 | |
|           }
 | |
|         } else {
 | |
|           //
 | |
|           // Wait for user's selection, no auto boot
 | |
|           //
 | |
|           Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);
 | |
|         }
 | |
|       } while (Status == EFI_TIMEOUT);
 | |
| 
 | |
|       if (gFirstIn) {
 | |
|         gFirstIn = FALSE;
 | |
|         gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
|         DisableQuietBoot ();
 | |
|       }
 | |
| 
 | |
|       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;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       switch (Key.UnicodeChar) {
 | |
|       case CHAR_CARRIAGE_RETURN:
 | |
|         Selection       = MenuOption;
 | |
|         ScreenOperation = UiSelect;
 | |
|         gDirection      = 0;
 | |
|         break;
 | |
| 
 | |
|       //
 | |
|       // We will push the adjustment of these numeric values directly to the input handler
 | |
|       //
 | |
|       case '+':
 | |
|       case '-':
 | |
|         if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
 | |
| 
 | |
|           if (Key.UnicodeChar == '+') {
 | |
|             gDirection = SCAN_RIGHT;
 | |
|           } else {
 | |
|             gDirection = SCAN_LEFT;
 | |
|           }
 | |
| 
 | |
|           Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case '^':
 | |
|         ScreenOperation = UiUp;
 | |
|         break;
 | |
| 
 | |
|       case 'V':
 | |
|       case 'v':
 | |
|         ScreenOperation = UiDown;
 | |
|         break;
 | |
| 
 | |
|       case ' ':
 | |
|         if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
 | |
|           if (SubMenu) {
 | |
|             if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {
 | |
|               gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
 | |
|               gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);
 | |
|               Selection       = MenuOption;
 | |
|               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) || (Key.ScanCode == SCAN_F10)) {
 | |
|                 if (SubMenu) {
 | |
|                   ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
 | |
|                 }
 | |
|               } else {
 | |
|                 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfScreenOperation:
 | |
|       IfrBinary = gBinaryDataHead;
 | |
| 
 | |
|       //
 | |
|       // Advance to the Ifr we are using
 | |
|       //
 | |
|       for (Index = 0; Index < gActiveIfr; Index++) {
 | |
|         IfrBinary = IfrBinary->Next;
 | |
|       }
 | |
| 
 | |
|       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 = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) {
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (Link == &Menu) {
 | |
|           ControlFlag = CfPrepareToReadKey;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       for (Index = 0;
 | |
|            Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
 | |
|            Index++
 | |
|           ) {
 | |
|         if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
 | |
|           ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case CfUiPrevious:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       //
 | |
|       // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.
 | |
|       //
 | |
|       if (MenuOption != NULL) {
 | |
|         if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
 | |
|           Selection = NULL;
 | |
|           Repaint   = TRUE;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (IsListEmpty (&gMenuList)) {
 | |
|         Selection = NULL;
 | |
|         if (IsListEmpty (&Menu)) {
 | |
|           ControlFlag = CfReadKey;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       gLastOpr = TRUE;
 | |
| 
 | |
|       while (gMenuRefreshHead != NULL) {
 | |
|         OldMenuRefreshEntry = gMenuRefreshHead->Next;
 | |
| 
 | |
|         FreePool (gMenuRefreshHead);
 | |
| 
 | |
|         gMenuRefreshHead = OldMenuRefreshEntry;
 | |
|       }
 | |
|       //
 | |
|       // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
 | |
|       //
 | |
|       if (SubMenu) {
 | |
|         UiRemoveMenuListEntry (MenuOption, &Selection);
 | |
|         Selection->Previous = TRUE;
 | |
|         UiFreeMenu ();
 | |
|         UiInitMenu ();
 | |
|       }
 | |
| 
 | |
|       gActiveIfr = Selection->IfrNumber;
 | |
|       return Selection;
 | |
| 
 | |
|     case CfUiSelect:
 | |
|       ControlFlag = CfCheckSelection;
 | |
| 
 | |
|       ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);
 | |
| 
 | |
|       if (SubMenu) {
 | |
|         if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP &&
 | |
|             !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) ||
 | |
|             (MenuOption->ThisTag->GrayOut) ||
 | |
|             (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
 | |
|             (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
 | |
|             Selection = NULL;
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|         NewLine = TRUE;
 | |
|         UpdateKeyHelp (MenuOption, TRUE);
 | |
|         Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);
 | |
| 
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           Selection = NULL;
 | |
|           Repaint   = TRUE;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (OptionString != NULL) {
 | |
|           PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);
 | |
|         }
 | |
| 
 | |
|         if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
 | |
|           Selection = MenuOption;
 | |
|         }
 | |
| 
 | |
|         if (Selection == NULL) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         Location = (UINT8 *) &PageData->EntryCount;
 | |
| 
 | |
|         //
 | |
|         // If not a goto, dump single piece of data, otherwise dump everything
 | |
|         //
 | |
|         if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) {
 | |
|           //
 | |
|           // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.
 | |
|           //
 | |
|           if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
 | |
|             Selection = NULL;
 | |
|             Repaint   = TRUE;
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           UiAddMenuListEntry (Selection);
 | |
|           gPriorMenuEntry = 0;
 | |
| 
 | |
|           //
 | |
|           // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
 | |
|           //
 | |
|           UiMenuList                    = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
 | |
|           UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;
 | |
| 
 | |
|           gLastOpr                      = FALSE;
 | |
| 
 | |
|           //
 | |
|           // Rewind to the beginning of the menu
 | |
|           //
 | |
|           for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)
 | |
|             ;
 | |
| 
 | |
|           //
 | |
|           // Get Total Count of Menu entries
 | |
|           //
 | |
|           for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {
 | |
|             Count++;
 | |
|           }
 | |
|           //
 | |
|           // Rewind to the beginning of the menu
 | |
|           //
 | |
|           for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)
 | |
|             ;
 | |
| 
 | |
|           //
 | |
|           // Copy the number of entries being described to the PageData location
 | |
|           //
 | |
|           CopyMem (&Location[0], &Count, sizeof (UINT32));
 | |
| 
 | |
|           for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {
 | |
| 
 | |
|             MenuOption          = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|             Location[Index]     = MenuOption->ThisTag->Operand;
 | |
|             Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);
 | |
|             CopyMem (
 | |
|               &Location[Index + 4],
 | |
|               &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],
 | |
|               MenuOption->ThisTag->StorageWidth
 | |
|               );
 | |
|             NewPos = NewPos->ForwardLink;
 | |
|           }
 | |
|         } else {
 | |
| 
 | |
|           gPriorMenuEntry = MenuOption->EntryNumber;
 | |
| 
 | |
|           Count           = 1;
 | |
| 
 | |
|           //
 | |
|           // Copy the number of entries being described to the PageData location
 | |
|           //
 | |
|           CopyMem (&Location[0], &Count, sizeof (UINT32));
 | |
| 
 | |
|           //
 | |
|           // Start at PageData[4] since the EntryCount is a UINT32
 | |
|           //
 | |
|           Index = 4;
 | |
| 
 | |
|           //
 | |
|           // Copy data to destination
 | |
|           //
 | |
|           Location[Index]     = MenuOption->ThisTag->Operand;
 | |
|           Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);
 | |
|           CopyMem (
 | |
|             &Location[Index + 4],
 | |
|             &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],
 | |
|             MenuOption->ThisTag->StorageWidth
 | |
|             );
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfUiReset:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       gLastOpr    = FALSE;
 | |
|       if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
 | |
|         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;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.
 | |
|       //
 | |
|       if (MenuOption != NULL) {
 | |
|         if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
 | |
|           Selection = NULL;
 | |
|           Repaint   = TRUE;
 | |
|           NewLine   = TRUE;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
|       gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | |
| 
 | |
|       if (SubMenu) {
 | |
|         UiFreeMenuList ();
 | |
|         gST->ConOut->ClearScreen (gST->ConOut);
 | |
|         return NULL;
 | |
|       }
 | |
| 
 | |
|       UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
 | |
|       UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);
 | |
| 
 | |
|       if (IfrBinary->UnRegisterOnExit) {
 | |
|         Hii->RemovePack (Hii, MenuOption->Handle);
 | |
|       }
 | |
| 
 | |
|       UiFreeMenu ();
 | |
| 
 | |
|       //
 | |
|       // Clean up the allocated data buffers
 | |
|       //
 | |
|       FreeData (FileFormTagsHead, FormattedString, OptionString);
 | |
| 
 | |
|       gST->ConOut->ClearScreen (gST->ConOut);
 | |
|       return NULL;
 | |
| 
 | |
|     case CfUiLeft:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
 | |
|         if (MenuOption->Skip == 1) {
 | |
|           //
 | |
|           // In the tail of the Date/Time op-code set, go left.
 | |
|           //
 | |
|           NewPos = NewPos->BackLink;
 | |
|         } else {
 | |
|           //
 | |
|           // In the middle of the Data/Time op-code set, go left.
 | |
|           //
 | |
|           NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           if (NextMenuOption->Skip == 1) {
 | |
|             NewPos = NewPos->BackLink;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfUiRight:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       if ((MenuOption->Skip == 0) &&
 | |
|           ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP))
 | |
|           ) {
 | |
|         //
 | |
|         // We are in the head or middle of the Date/Time op-code set, advance right.
 | |
|         //
 | |
|         NewPos = NewPos->ForwardLink;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfUiUp:
 | |
|       ControlFlag = CfCheckSelection;
 | |
| 
 | |
|       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 = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|         //
 | |
|         // 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.
 | |
|         //
 | |
|         DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);
 | |
| 
 | |
|         if (SubMenu) {
 | |
|           //
 | |
|           // If the previous MenuOption contains a display-only op-code, skip to the next one
 | |
|           //
 | |
|           if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {
 | |
|             //
 | |
|             // This is ok as long as not at the end of the list
 | |
|             //
 | |
|             if (NewPos->BackLink == &Menu) {
 | |
|               //
 | |
|               // If we are at the start of the list, then this list must start with a display only
 | |
|               // piece of data, so do not allow the backward motion
 | |
|               //
 | |
|               ScreenOperation = UiDown;
 | |
| 
 | |
|               if (PreviousMenuOption->Row <= TopRow) {
 | |
|                 if (TopOfScreen->BackLink != &Menu) {
 | |
|                   TopOfScreen = TopOfScreen->BackLink;
 | |
|                   Repaint     = TRUE;
 | |
|                 }
 | |
|               }
 | |
| 
 | |
|               UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         //
 | |
|         // Check the previous menu entry to see if it was a zero-length advance.  If it was,
 | |
|         // don't worry about a redraw.
 | |
|         //
 | |
|         if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||
 | |
|             (PreviousMenuOption->Skip > MenuOption->Row)
 | |
|             ) {
 | |
|           do {
 | |
|             if (TopOfScreen->BackLink == &Menu) {
 | |
|               break;
 | |
|             }
 | |
| 
 | |
|             Repaint = TRUE;
 | |
| 
 | |
|             //
 | |
|             // 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 = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|             TopOfScreen     = TopOfScreen->BackLink;
 | |
|           } while (SavedMenuOption->Skip == 0);
 | |
|           //
 | |
|           // 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->Flags, FALSE);
 | |
|       } else {
 | |
|         if (SubMenu) {
 | |
|           SavedMenuOption = MenuOption;
 | |
|           MenuOption      = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
 | |
|             //
 | |
|             // 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;
 | |
| 
 | |
|       SavedListEntry  = NewPos;
 | |
|       Link            = TopOfScreen;
 | |
|       for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {
 | |
|         if (Link->BackLink == &Menu) {
 | |
|           TopOfScreen = Link;
 | |
|           Link        = SavedListEntry;
 | |
|           MenuOption  = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         NewLine         = TRUE;
 | |
|         Repaint         = TRUE;
 | |
|         Link            = Link->BackLink;
 | |
|         MenuOption      = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|         TopOfScreen     = Link;
 | |
|         SavedListEntry  = Link;
 | |
|       }
 | |
| 
 | |
|       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.
 | |
|       //
 | |
|       if (Repaint) {
 | |
|         AdjustDateAndTimePosition (TRUE, &TopOfScreen);
 | |
|         AdjustDateAndTimePosition (TRUE, &NewPos);
 | |
|         MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case CfUiPageDown:
 | |
|       ControlFlag     = CfCheckSelection;
 | |
| 
 | |
|       SavedListEntry  = NewPos;
 | |
|       Link            = TopOfScreen;
 | |
|       NewPos          = TopOfScreen;
 | |
|       for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {
 | |
|         if (NewPos->ForwardLink == &Menu) {
 | |
|           NewPos      = SavedListEntry;
 | |
|           MenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           Link        = TopOfScreen;
 | |
|           NewLine     = FALSE;
 | |
|           Repaint     = FALSE;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         NewLine     = TRUE;
 | |
|         Repaint     = TRUE;
 | |
|         MenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|         NewPos      = NewPos->ForwardLink;
 | |
|         Link        = NewPos;
 | |
|       }
 | |
| 
 | |
|       TopOfScreen = 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.
 | |
|       //
 | |
|       if (Repaint) {
 | |
|         AdjustDateAndTimePosition (TRUE, &TopOfScreen);
 | |
|         AdjustDateAndTimePosition (TRUE, &NewPos);
 | |
|         MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|       }
 | |
|       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.
 | |
|       //
 | |
|       DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);
 | |
| 
 | |
|       if (NewPos->ForwardLink != &Menu) {
 | |
|         NewLine         = TRUE;
 | |
|         NewPos          = NewPos->ForwardLink;
 | |
|         NextMenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|         if (SubMenu) {
 | |
|           //
 | |
|           // If the next MenuOption contains a display-only op-code, skip to the next one
 | |
|           // Also if the next MenuOption is date or time,
 | |
|           //
 | |
|           if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {
 | |
|             //
 | |
|             // This is ok as long as not at the end of the list
 | |
|             //
 | |
|             if (NewPos == &Menu) {
 | |
|               //
 | |
|               // If we are at the end of the list, then this list must end with a display only
 | |
|               // piece of data, so do not allow the forward motion
 | |
|               //
 | |
|               UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);
 | |
|               NewPos          = NewPos->BackLink;
 | |
|               ScreenOperation = UiUp;
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         //
 | |
|         // An option might be multi-line, so we need to reflect that data in the overall skip value
 | |
|         //
 | |
|         UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);
 | |
| 
 | |
|         if (NextMenuOption->Skip > 1) {
 | |
|           Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;
 | |
|         } else {
 | |
|           Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;
 | |
|         }
 | |
|         //
 | |
|         // If we are going to scroll
 | |
|         //
 | |
|         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 = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|             //
 | |
|             // If bottom op-code is more than one line or top op-code is more than one line
 | |
|             //
 | |
|             if ((NextMenuOption->Skip > 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 = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|                 //
 | |
|                 // 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 = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|                   if (Difference < (INTN) SavedMenuOption->Skip) {
 | |
|                     Difference = SavedMenuOption->Skip - Difference - 1;
 | |
|                     break;
 | |
|                   } else {
 | |
|                     if (Difference == (INTN) SavedMenuOption->Skip) {
 | |
|                       TopOfScreen     = TopOfScreen->ForwardLink;
 | |
|                       SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|                       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;
 | |
|         }
 | |
| 
 | |
|         UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
 | |
| 
 | |
|       } else {
 | |
|         if (SubMenu) {
 | |
|           SavedMenuOption = MenuOption;
 | |
|           MenuOption      = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|           if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {
 | |
|             //
 | |
|             // 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;
 | |
|       //
 | |
|       // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.
 | |
|       //
 | |
|       if (MenuOption != NULL) {
 | |
|         if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {
 | |
|           Selection = NULL;
 | |
|           Repaint   = TRUE;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // If callbacks are active, and the callback has a Write method, try to use it
 | |
|       //
 | |
|       if (FileFormTags->VariableDefinitions->VariableName == NULL) {
 | |
|         if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {
 | |
|           Status = FormCallback->NvWrite (
 | |
|                                   FormCallback,
 | |
|                                   (CHAR16 *) L"Setup",
 | |
|                                   &FileFormTags->FormTags.Tags[0].GuidValue,
 | |
|                                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                                   VariableDefinition->VariableSize,
 | |
|                                   (VOID *) VariableDefinition->NvRamMap,
 | |
|                                   &gResetRequired
 | |
|                                   );
 | |
| 
 | |
|         } else {
 | |
|           Status = gRT->SetVariable (
 | |
|                           (CHAR16 *) L"Setup",
 | |
|                           &FileFormTags->FormTags.Tags[0].GuidValue,
 | |
|                           EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                           VariableDefinition->VariableSize,
 | |
|                           (VOID *) VariableDefinition->NvRamMap
 | |
|                           );
 | |
|         }
 | |
|       } else {
 | |
|         VariableDefinition = FileFormTags->VariableDefinitions;
 | |
| 
 | |
|         for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
 | |
|           if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {
 | |
|             Status = FormCallback->NvWrite (
 | |
|                                     FormCallback,
 | |
|                                     VariableDefinition->VariableName,
 | |
|                                     &VariableDefinition->Guid,
 | |
|                                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                                     VariableDefinition->VariableSize,
 | |
|                                     (VOID *) VariableDefinition->NvRamMap,
 | |
|                                     &gResetRequired
 | |
|                                     );
 | |
| 
 | |
|           } else {
 | |
|             Status = gRT->SetVariable (
 | |
|                             VariableDefinition->VariableName,
 | |
|                             &VariableDefinition->Guid,
 | |
|                             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                             VariableDefinition->VariableSize,
 | |
|                             (VOID *) VariableDefinition->NvRamMap
 | |
|                             );
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);
 | |
|       UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);
 | |
|       break;
 | |
| 
 | |
|     case CfUiDefault:
 | |
|       ControlFlag = CfCheckSelection;
 | |
| 
 | |
|       NvMapListHead = NULL;
 | |
| 
 | |
|       Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead);
 | |
| 
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         ASSERT_EFI_ERROR (NULL != NvMapListHead);
 | |
| 
 | |
|         NvMapListNode = NvMapListHead;
 | |
| 
 | |
|         while (NULL != NvMapListNode) {
 | |
|           
 | |
|           for (UiDefaultVarDef = FileFormTags->VariableDefinitions;
 | |
|                 UiDefaultVarDef != NULL; 
 | |
|                 UiDefaultVarDef = UiDefaultVarDef->Next ) {
 | |
|                 
 | |
|             if (UiDefaultVarDef->VariableId == NvMapListNode->VariablePack->VariableId) {
 | |
|               NvMap     = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);
 | |
|               NvMapSize = NvMapListNode->VariablePack->Header.Length  - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;
 | |
|               //
 | |
|               // Free the buffer that was allocated.
 | |
|               //
 | |
|               FreePool (UiDefaultVarDef->NvRamMap);
 | |
|               FreePool (UiDefaultVarDef->FakeNvRamMap);
 | |
|               
 | |
|               //
 | |
|               // Allocate, copy the NvRamMap.
 | |
|               //
 | |
|               UiDefaultVarDef->VariableFakeSize = (UINT16) (UiDefaultVarDef->VariableFakeSize - UiDefaultVarDef->VariableSize);
 | |
|               UiDefaultVarDef->VariableSize = (UINT16) NvMapSize;
 | |
|               UiDefaultVarDef->VariableFakeSize = (UINT16) (UiDefaultVarDef->VariableFakeSize + UiDefaultVarDef->VariableSize);
 | |
|               
 | |
|               UiDefaultVarDef->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);
 | |
|               ASSERT (UiDefaultVarDef->NvRamMap != NULL);
 | |
|               
 | |
|               UiDefaultVarDef->FakeNvRamMap = AllocateZeroPool (NvMapSize + UiDefaultVarDef->VariableFakeSize);
 | |
|               ASSERT (UiDefaultVarDef->FakeNvRamMap != NULL);
 | |
|               
 | |
|               CopyMem (UiDefaultVarDef->NvRamMap, NvMap, NvMapSize);
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|           NvMapListNode = NvMapListNode->NextVariablePack;
 | |
|         }
 | |
| 
 | |
|         FreePool (NvMapListHead);
 | |
|       }
 | |
| 
 | |
|       UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);
 | |
|       Repaint = TRUE;
 | |
|       //
 | |
|       // After the repaint operation, we should refresh the highlight.
 | |
|       //
 | |
|       NewLine    = TRUE;
 | |
|       break;
 | |
| 
 | |
|     case CfUiNoOperation:
 | |
|       ControlFlag = CfCheckSelection;
 | |
|       break;
 | |
| 
 | |
|     case CfExit:
 | |
|       while (gMenuRefreshHead != NULL) {
 | |
|         OldMenuRefreshEntry = gMenuRefreshHead->Next;
 | |
| 
 | |
|         FreePool (gMenuRefreshHead);
 | |
| 
 | |
|         gMenuRefreshHead = OldMenuRefreshEntry;
 | |
|       }
 | |
| 
 | |
|       gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);
 | |
|       gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | |
|       gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");
 | |
| 
 | |
|       gActiveIfr = MenuOption->IfrNumber;
 | |
|       return Selection;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| ValueIsScroll (
 | |
|   IN  BOOLEAN                 Direction,
 | |
|   IN  LIST_ENTRY              *CurrentPos
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Determine if the menu is the last menu that can be selected.
 | |
| 
 | |
| Arguments:
 | |
|   Direction - the scroll direction. False is down. True is up.
 | |
| 
 | |
| Returns:
 | |
|   FALSE -- the menu isn't the last menu that can be selected.
 | |
|   TRUE  -- the menu is the last menu that can be selected.
 | |
| --*/
 | |
| {
 | |
|   LIST_ENTRY      *Temp;
 | |
|   UI_MENU_OPTION  *MenuOption;
 | |
|   MenuOption  = NULL;
 | |
| 
 | |
|   Temp        = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
 | |
| 
 | |
|   if (Temp == &Menu) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {
 | |
|     MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|     if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| UINTN
 | |
| AdjustDateAndTimePosition (
 | |
|   IN  BOOLEAN                 DirectionUp,
 | |
|   IN  LIST_ENTRY              **CurrentPosition
 | |
|   )
 | |
| /*++
 | |
| Routine Description:
 | |
|   Adjust Data and Time tag position accordingly.
 | |
|   Data format :      [01/02/2004]      [11:22:33]
 | |
|   Line number :        0  0    1         0  0  1
 | |
| 
 | |
| Arguments:
 | |
|   Direction - the up or down direction. False is down. True is up.
 | |
|   CurrentPos - Current position.
 | |
| 
 | |
| Returns:
 | |
|   Return line number to pad. It is possible that we stand on a zero-advance
 | |
|   data or time opcode, so pad one line when we judge if we are going to scroll outside.
 | |
| --*/
 | |
| {
 | |
|   UINTN           Count;
 | |
|   LIST_ENTRY      *NewPosition;
 | |
|   UI_MENU_OPTION  *MenuOption;
 | |
|   UINTN           PadLineNumber;
 | |
| 
 | |
|   PadLineNumber = 0;
 | |
|   NewPosition   = *CurrentPosition;
 | |
|   MenuOption    = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
| 
 | |
|   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 op-code.
 | |
|     //
 | |
|     Count = 0;
 | |
|     while (MenuOption->ThisTag->NumberOfLines == 0) {
 | |
|       Count++;
 | |
|       NewPosition   = NewPosition->ForwardLink;
 | |
|       MenuOption    = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);
 | |
|       PadLineNumber = 1;
 | |
|     }
 | |
| 
 | |
|     NewPosition = *CurrentPosition;
 | |
|     if (DirectionUp) {
 | |
|       //
 | |
|       // 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 first
 | |
|       // Date/Time op-code 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 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 CfUiDown intact so the appropriate
 | |
|       // checking can be done.
 | |
|       //
 | |
|       while (Count-- > 0) {
 | |
|         NewPosition = NewPosition->ForwardLink;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     *CurrentPosition = NewPosition;
 | |
|   }
 | |
| 
 | |
|   return PadLineNumber;
 | |
| }
 |