4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
32 Set Buffer to Value for Size bytes.
36 Buffer - Memory to set.
38 Size - Number of bytes to set
40 Value - Value of the set operation.
63 Initialize Menu option list.
71 InitializeListHead (&Menu
);
81 Initialize Menu option list.
89 InitializeListHead (&gMenuList
);
93 UiRemoveMenuListEntry (
94 IN UI_MENU_OPTION
*Selection
,
95 OUT UI_MENU_OPTION
**PreviousSelection
100 Remove Menu option list.
108 UI_MENU_LIST
*UiMenuList
;
110 *PreviousSelection
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
111 ASSERT (*PreviousSelection
!= NULL
);
113 if (!IsListEmpty (&gMenuList
)) {
114 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
115 (*PreviousSelection
)->IfrNumber
= UiMenuList
->Selection
.IfrNumber
;
116 (*PreviousSelection
)->FormId
= UiMenuList
->Selection
.FormId
;
117 (*PreviousSelection
)->Tags
= UiMenuList
->Selection
.Tags
;
118 (*PreviousSelection
)->ThisTag
= UiMenuList
->Selection
.ThisTag
;
119 (*PreviousSelection
)->Handle
= UiMenuList
->Selection
.Handle
;
120 gEntryNumber
= UiMenuList
->FormerEntryNumber
;
121 RemoveEntryList (&UiMenuList
->MenuLink
);
122 gBS
->FreePool (UiMenuList
);
133 Free Menu option linked list.
141 UI_MENU_LIST
*UiMenuList
;
143 while (!IsListEmpty (&gMenuList
)) {
144 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
145 RemoveEntryList (&UiMenuList
->MenuLink
);
146 gBS
->FreePool (UiMenuList
);
152 IN UI_MENU_OPTION
*Selection
157 Add one menu entry to the linked lst
165 UI_MENU_LIST
*UiMenuList
;
167 UiMenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
168 ASSERT (UiMenuList
!= NULL
);
170 UiMenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
171 CopyMem (&UiMenuList
->Selection
, Selection
, sizeof (UI_MENU_OPTION
));
173 InsertHeadList (&gMenuList
, &UiMenuList
->MenuLink
);
183 Free Menu option linked list.
191 UI_MENU_OPTION
*MenuOption
;
193 while (!IsListEmpty (&Menu
)) {
194 MenuOption
= CR (Menu
.ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
195 RemoveEntryList (&MenuOption
->Link
);
198 // We allocated space for this description when we did a GetToken, free it here
200 gBS
->FreePool (MenuOption
->Description
);
201 gBS
->FreePool (MenuOption
);
213 Refresh screen with current date and/or time based on screen context
221 CHAR16
*OptionString
;
222 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
228 if (gMenuRefreshHead
!= NULL
) {
230 MenuRefreshEntry
= gMenuRefreshHead
;
233 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
234 ProcessOptions (MenuRefreshEntry
->MenuOption
, FALSE
, MenuRefreshEntry
->FileFormTagsHead
, NULL
, &OptionString
);
236 if (OptionString
!= NULL
) {
238 // If leading spaces on OptionString - remove the spaces
240 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
243 for (Loop
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
244 OptionString
[Loop
] = OptionString
[Index
];
248 OptionString
[Loop
] = CHAR_NULL
;
250 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, OptionString
);
253 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
255 } while (MenuRefreshEntry
!= NULL
);
258 if (OptionString
!= NULL
) {
259 gBS
->FreePool (OptionString
);
264 UiWaitForSingleEvent (
266 IN UINT64 Timeout OPTIONAL
271 Wait for a given event to fire, or for an optional timeout to expire.
274 Event - The event to wait for
276 Timeout - An optional timeout value in 100 ns units.
280 EFI_SUCCESS - Event fired before Timeout expired.
281 EFI_TIME_OUT - Timout expired before Event fired.
287 EFI_EVENT TimerEvent
;
288 EFI_EVENT WaitList
[2];
292 // Create a timer event
294 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
295 if (!EFI_ERROR (Status
)) {
297 // Set the timer event
306 // Wait for the original event or the timer
309 WaitList
[1] = TimerEvent
;
310 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
311 gBS
->CloseEvent (TimerEvent
);
314 // If the timer expired, change the return to timed out
316 if (!EFI_ERROR (Status
) && Index
== 1) {
317 Status
= EFI_TIMEOUT
;
322 // Update screen every second
324 Timeout
= ONE_SECOND
;
327 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
330 // Set the timer event
339 // Wait for the original event or the timer
342 WaitList
[1] = TimerEvent
;
343 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
346 // If the timer expired, update anything that needs a refresh and keep waiting
348 if (!EFI_ERROR (Status
) && Index
== 1) {
349 Status
= EFI_TIMEOUT
;
350 UpdateDateAndTime ();
353 gBS
->CloseEvent (TimerEvent
);
354 } while (Status
== EFI_TIMEOUT
);
363 IN EFI_HII_HANDLE Handle
,
371 Add one menu option by specified description and context.
374 String - String description for this option.
375 Context - Context data for entry.
381 UI_MENU_OPTION
*MenuOption
;
383 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
386 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
387 MenuOption
->Description
= String
;
388 MenuOption
->Handle
= Handle
;
389 MenuOption
->FormBinary
= FormBinary
;
390 MenuOption
->IfrNumber
= IfrNumber
;
391 MenuOption
->Skip
= 1;
392 MenuOption
->Tags
= Tags
;
393 MenuOption
->TagIndex
= 0;
394 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
395 MenuOption
->EntryNumber
= (UINT16
) IfrNumber
;
397 InsertTailList (&Menu
, &MenuOption
->Link
);
403 IN EFI_HII_HANDLE Handle
,
407 IN UINT16 MenuItemCount
412 Add one menu option by specified description and context.
415 String - String description for this option.
416 Context - Context data for entry.
422 UI_MENU_OPTION
*MenuOption
;
424 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
427 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
428 MenuOption
->Description
= String
;
429 MenuOption
->Handle
= Handle
;
430 MenuOption
->Skip
= Tags
[TagIndex
].NumberOfLines
;
431 MenuOption
->IfrNumber
= gActiveIfr
;
432 MenuOption
->Tags
= Tags
;
433 MenuOption
->TagIndex
= TagIndex
;
434 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
435 MenuOption
->Consistency
= Tags
[TagIndex
].Consistency
;
436 MenuOption
->FormId
= FormId
;
437 MenuOption
->GrayOut
= Tags
[TagIndex
].GrayOut
;
438 MenuOption
->EntryNumber
= MenuItemCount
;
440 InsertTailList (&Menu
, &MenuOption
->Link
);
445 IN UINTN NumberOfLines
,
447 IN UINTN MaximumStringSize
,
448 OUT CHAR16
*StringBuffer
,
449 OUT EFI_INPUT_KEY
*KeyValue
,
456 Routine used to abstract a generic dialog interface and return the selected key or string
459 NumberOfLines - The number of lines for the dialog box
460 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue
461 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and
462 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns
463 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
464 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
465 KeyValue - The EFI_KEY value returned if HotKey is TRUE..
466 String - Pointer to the first string in the list
467 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
470 EFI_SUCCESS - Displayed dialog and received user interaction
471 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
472 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine
481 CHAR16
*BufferedString
;
487 BOOLEAN SelectionComplete
;
489 UINTN CurrentAttribute
;
490 UINTN DimensionsWidth
;
491 UINTN DimensionsHeight
;
493 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
494 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
496 SelectionComplete
= FALSE
;
498 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
499 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
500 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
503 ASSERT (BufferedString
);
505 VA_START (Marker
, String
);
508 // Zero the outgoing buffer
510 ZeroMem (StringBuffer
, MaximumStringSize
);
513 if (KeyValue
== NULL
) {
514 return EFI_INVALID_PARAMETER
;
517 if (StringBuffer
== NULL
) {
518 return EFI_INVALID_PARAMETER
;
524 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
526 LargestString
= (GetStringWidth (String
) / 2);
528 if (LargestString
== L
' ') {
532 // Determine the largest string in the dialog box
533 // Notice we are starting with 1 since String is the first string
535 for (Count
= 1; Count
< NumberOfLines
; Count
++) {
536 StackString
= VA_ARG (Marker
, CHAR16
*);
538 if (StackString
[0] == L
' ') {
539 InputOffset
= Count
+ 1;
542 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
544 // Size of the string visually and subtract the width by one for the null-terminator
546 LargestString
= (GetStringWidth (StackString
) / 2);
550 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
551 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
558 CreateSharedPopUp (LargestString
, NumberOfLines
, &String
);
561 // Take the first key typed and report it back?
564 WaitForKeyStroke (&Key
);
565 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
569 WaitForKeyStroke (&Key
);
571 switch (Key
.UnicodeChar
) {
573 switch (Key
.ScanCode
) {
575 gBS
->FreePool (TempString
);
576 gBS
->FreePool (BufferedString
);
577 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
578 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
579 return EFI_DEVICE_ERROR
;
587 case CHAR_CARRIAGE_RETURN
:
588 SelectionComplete
= TRUE
;
589 gBS
->FreePool (TempString
);
590 gBS
->FreePool (BufferedString
);
591 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
592 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
597 if (StringBuffer
[0] != CHAR_NULL
) {
598 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
599 TempString
[Index
] = StringBuffer
[Index
];
602 // Effectively truncate string by 1 character
604 TempString
[Index
- 1] = CHAR_NULL
;
605 StrCpy (StringBuffer
, TempString
);
610 // If it is the beginning of the string, don't worry about checking maximum limits
612 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
613 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
614 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
615 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
616 KeyPad
[0] = Key
.UnicodeChar
;
617 KeyPad
[1] = CHAR_NULL
;
618 StrCat (StringBuffer
, KeyPad
);
619 StrCat (TempString
, KeyPad
);
622 // If the width of the input string is now larger than the screen, we nee to
623 // adjust the index to start printing portions of the string
625 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
627 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
629 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
630 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
635 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
636 BufferedString
[Count
] = StringBuffer
[Index
];
639 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
642 } while (!SelectionComplete
);
645 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
646 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
652 IN UINTN RequestedWidth
,
653 IN UINTN NumberOfLines
,
654 IN CHAR16
**ArrayOfStrings
666 UINTN DimensionsWidth
;
667 UINTN DimensionsHeight
;
669 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
670 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
674 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
676 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
677 RequestedWidth
= DimensionsWidth
- 2;
680 // Subtract the PopUp width from total Columns, allow for one space extra on
681 // each end plus a border.
683 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
684 End
= Start
+ RequestedWidth
+ 1;
686 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
687 Bottom
= Top
+ NumberOfLines
+ 2;
689 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
690 PrintCharAt (Start
, Top
, Character
);
691 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
692 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
693 PrintChar (Character
);
696 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
697 PrintChar (Character
);
698 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
699 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++) {
700 String
= ArrayOfStrings
[Count
];
704 // This will clear the background of the line - we never know who might have been
705 // here before us. This differs from the next clear in that it used the non-reverse
706 // video for normal printing.
708 if (GetStringWidth (String
) / 2 > 1) {
709 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
712 // Passing in a space results in the assumption that this is where typing will occur
714 if (String
[0] == L
' ') {
715 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
718 // Passing in a NULL results in a blank space
720 if (String
[0] == CHAR_NULL
) {
721 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
725 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
729 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
730 PrintCharAt (Start
, Index
+ 1, Character
);
731 PrintCharAt (End
- 1, Index
+ 1, Character
);
734 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
735 PrintCharAt (Start
, Bottom
- 1, Character
);
736 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
737 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
738 PrintChar (Character
);
741 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
742 PrintChar (Character
);
747 IN UINTN RequestedWidth
,
748 IN UINTN NumberOfLines
,
749 IN CHAR16
*ArrayOfStrings
,
753 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, &ArrayOfStrings
);
758 IN UINTN MessageType
,
764 STATIC BOOLEAN InputError
;
765 CHAR16
*NvUpdateMessage
;
766 CHAR16
*InputErrorMessage
;
768 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
769 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
771 switch (MessageType
) {
774 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
776 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
777 gScreenDimensions
.BottomRow
- 1,
782 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
783 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
784 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, (CHAR16
*) L
" ");
791 case NV_UPDATE_REQUIRED
:
792 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
794 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
796 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
797 gScreenDimensions
.BottomRow
- 1,
800 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
802 gNvUpdateRequired
= TRUE
;
804 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
805 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
807 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
808 gScreenDimensions
.BottomRow
- 1,
813 gNvUpdateRequired
= FALSE
;
818 case REFRESH_STATUS_BAR
:
820 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
823 if (gNvUpdateRequired
) {
824 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
832 gBS
->FreePool (InputErrorMessage
);
833 gBS
->FreePool (NvUpdateMessage
);
839 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
840 IN CHAR16
*FormattedString
,
841 IN CHAR16
*OptionString
847 Used to remove the allocated data instances
855 EFI_FILE_FORM_TAGS
*FileForm
;
856 EFI_FILE_FORM_TAGS
*PreviousFileForm
;
857 EFI_FORM_TAGS
*FormTags
;
858 EFI_FORM_TAGS
*PreviousFormTags
;
859 EFI_IFR_BINARY
*IfrBinary
;
860 EFI_IFR_BINARY
*PreviousIfrBinary
;
861 EFI_INCONSISTENCY_DATA
*Inconsistent
;
862 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
863 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinition
;
867 FileForm
= FileFormTagsHead
;
869 if (FormattedString
!= NULL
) {
870 gBS
->FreePool (FormattedString
);
873 if (OptionString
!= NULL
) {
874 gBS
->FreePool (OptionString
);
877 for (; FileForm
!= NULL
;) {
878 PreviousFileForm
= NULL
;
881 // Advance FileForm to the last entry
883 for (; FileForm
->NextFile
!= NULL
; FileForm
= FileForm
->NextFile
) {
884 PreviousFileForm
= FileForm
;
887 FormTags
= &FileForm
->FormTags
;
889 for (; FormTags
!= NULL
;) {
890 FormTags
= &FileForm
->FormTags
;
891 PreviousFormTags
= NULL
;
894 // Advance FormTags to the last entry
896 for (; FormTags
->Next
!= NULL
; FormTags
= FormTags
->Next
) {
897 PreviousFormTags
= FormTags
;
900 // Walk through each of the tags and free the IntList allocation
902 for (Index
= 0; FormTags
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
; Index
++) {
904 // It is more than likely that the very last page will contain an end formset
906 if (FormTags
->Tags
[Index
].Operand
== EFI_IFR_END_FORM_SET_OP
) {
910 if (FormTags
->Tags
[Index
].IntList
!= NULL
) {
911 gBS
->FreePool (FormTags
->Tags
[Index
].IntList
);
915 if (PreviousFormTags
!= NULL
) {
916 gBS
->FreePool (FormTags
->Tags
);
917 FormTags
= PreviousFormTags
;
918 gBS
->FreePool (FormTags
->Next
);
919 FormTags
->Next
= NULL
;
921 gBS
->FreePool (FormTags
->Tags
);
926 // Last FileForm entry's Inconsistent database
928 Inconsistent
= FileForm
->InconsistentTags
;
931 // Advance Inconsistent to the last entry
933 for (; Inconsistent
->Next
!= NULL
; Inconsistent
= Inconsistent
->Next
)
936 for (; Inconsistent
!= NULL
;) {
938 // Preserve the Previous pointer
940 Buffer
= (VOID
*) Inconsistent
->Previous
;
943 // Free the current entry
945 gBS
->FreePool (Inconsistent
);
948 // Restore the Previous pointer
950 Inconsistent
= (EFI_INCONSISTENCY_DATA
*) Buffer
;
953 VariableDefinition
= FileForm
->VariableDefinitions
;
955 for (; VariableDefinition
!= NULL
;) {
956 VariableDefinition
= FileForm
->VariableDefinitions
;
957 PreviousVariableDefinition
= NULL
;
960 // Advance VariableDefinitions to the last entry
962 for (; VariableDefinition
->Next
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
963 PreviousVariableDefinition
= VariableDefinition
;
966 gBS
->FreePool (VariableDefinition
->VariableName
);
967 gBS
->FreePool (VariableDefinition
->NvRamMap
);
968 gBS
->FreePool (VariableDefinition
->FakeNvRamMap
);
970 if (PreviousVariableDefinition
!= NULL
) {
971 VariableDefinition
= PreviousVariableDefinition
;
972 gBS
->FreePool (VariableDefinition
->Next
);
973 VariableDefinition
->Next
= NULL
;
975 gBS
->FreePool (VariableDefinition
);
976 VariableDefinition
= NULL
;
980 if (PreviousFileForm
!= NULL
) {
981 FileForm
= PreviousFileForm
;
982 gBS
->FreePool (FileForm
->NextFile
);
983 FileForm
->NextFile
= NULL
;
985 gBS
->FreePool (FileForm
);
990 IfrBinary
= gBinaryDataHead
;
992 for (; IfrBinary
!= NULL
;) {
993 IfrBinary
= gBinaryDataHead
;
994 PreviousIfrBinary
= NULL
;
997 // Advance IfrBinary to the last entry
999 for (; IfrBinary
->Next
!= NULL
; IfrBinary
= IfrBinary
->Next
) {
1000 PreviousIfrBinary
= IfrBinary
;
1003 gBS
->FreePool (IfrBinary
->IfrPackage
);
1005 if (PreviousIfrBinary
!= NULL
) {
1006 IfrBinary
= PreviousIfrBinary
;
1007 gBS
->FreePool (IfrBinary
->Next
);
1008 IfrBinary
->Next
= NULL
;
1010 gBS
->FreePool (IfrBinary
);
1015 gBS
->FreePool (gPreviousValue
);
1016 gPreviousValue
= NULL
;
1019 // Free Browser Strings
1021 gBS
->FreePool (gPressEnter
);
1022 gBS
->FreePool (gConfirmError
);
1023 gBS
->FreePool (gConfirmPassword
);
1024 gBS
->FreePool (gPromptForNewPassword
);
1025 gBS
->FreePool (gPromptForPassword
);
1026 gBS
->FreePool (gToggleCheckBox
);
1027 gBS
->FreePool (gNumericInput
);
1028 gBS
->FreePool (gMakeSelection
);
1029 gBS
->FreePool (gMoveHighlight
);
1030 gBS
->FreePool (gEscapeString
);
1031 gBS
->FreePool (gEnterCommitString
);
1032 gBS
->FreePool (gEnterString
);
1033 gBS
->FreePool (gFunctionOneString
);
1034 gBS
->FreePool (gFunctionTwoString
);
1035 gBS
->FreePool (gFunctionNineString
);
1036 gBS
->FreePool (gFunctionTenString
);
1042 SelectionsAreValid (
1043 IN UI_MENU_OPTION
*MenuOption
,
1044 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
1048 Routine Description:
1049 Initiate late consistency checks against the current page.
1060 EFI_FILE_FORM_TAGS
*FileFormTags
;
1062 CHAR16 NullCharacter
;
1067 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1069 StringPtr
= (CHAR16
*) L
"\0";
1070 NullCharacter
= CHAR_NULL
;
1072 FileFormTags
= FileFormTagsHead
;
1074 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
1075 FileFormTags
= FileFormTags
->NextFile
;
1078 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1079 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1081 Tag
= MenuOption
->ThisTag
;
1083 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
1084 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1087 // If the op-code has a late check, ensure consistency checks are now applied
1089 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
1090 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
1091 if (PopUp
!= 0x0000) {
1092 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
1094 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
1097 WaitForKeyStroke (&Key
);
1099 switch (Key
.UnicodeChar
) {
1101 case CHAR_CARRIAGE_RETURN
:
1103 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
1105 CopyMem (NvRamMap
, &Tag
->OldValue
, Tag
->StorageWidth
);
1106 gBS
->FreePool (StringPtr
);
1112 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1126 IN EFI_HII_HANDLE Handle
1130 Routine Description:
1131 Get the supported width for a particular op-code
1134 Tag - The Tag structure passed in.
1135 Handle - The handle in the HII database being used
1138 Returns the number of CHAR16 characters that is support.
1149 // See if the second text parameter is really NULL
1151 if ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Tag
->TextTwo
!= 0)) {
1152 String
= GetToken (Tag
->TextTwo
, Handle
);
1153 Size
= StrLen (String
);
1154 gBS
->FreePool (String
);
1157 if ((Tag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1158 (Tag
->Operand
== EFI_IFR_REF_OP
) ||
1159 (Tag
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1160 (Tag
->Operand
== EFI_IFR_STRING_OP
) ||
1161 (Tag
->Operand
== EFI_IFR_INVENTORY_OP
) ||
1163 // Allow a wide display if text op-code and no secondary text op-code
1165 ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0x0000))
1167 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1169 return (UINT16
) gPromptBlockWidth
;
1175 IN CHAR16
*InputString
,
1176 IN UINT16 LineWidth
,
1177 IN OUT UINTN
*Index
,
1178 OUT CHAR16
**OutputString
1182 Routine Description:
1183 Will copy LineWidth amount of a string in the OutputString buffer and return the
1184 number of CHAR16 characters that were copied into the OutputString buffer.
1187 InputString - String description for this option.
1188 LineWidth - Width of the desired string to extract in CHAR16 characters
1189 Index - Where in InputString to start the copy process
1190 OutputString - Buffer to copy the string into
1193 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1198 static BOOLEAN Finished
;
1210 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1213 // Ensure we have got a valid buffer
1215 if (*OutputString
!= NULL
) {
1218 //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.
1219 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1221 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1222 *Index
= *Index
+ 2;
1226 // Fast-forward the string and see if there is a carriage-return in the string
1228 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1232 // Copy the desired LineWidth of data to the output buffer.
1233 // Also make sure that we don't copy more than the string.
1234 // Also make sure that if there are linefeeds, we account for them.
1236 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1237 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1240 // Convert to CHAR16 value and show that we are done with this operation
1242 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1243 if (LineWidth
!= 0) {
1247 if (Count2
== LineWidth
) {
1249 // Rewind the string from the maximum size until we see a space to break the line
1251 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1253 if (LineWidth
== 0) {
1261 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1264 // If currently pointing to a space, increment the index to the first non-space character
1267 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1271 *Index
= (UINT16
) (*Index
+ LineWidth
);
1280 UpdateOptionSkipLines (
1281 IN EFI_IFR_DATA_ARRAY
*PageData
,
1282 IN UI_MENU_OPTION
*MenuOption
,
1283 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1284 IN CHAR16
**OptionalString
,
1292 CHAR16
*OutputString
;
1293 CHAR16
*OptionString
;
1296 OptionString
= *OptionalString
;
1297 OutputString
= NULL
;
1299 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1301 if (OptionString
!= NULL
) {
1302 Width
= (UINT16
) gOptionBlockWidth
;
1306 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1308 // If there is more string to process print on the next row and increment the Skip value
1310 if (StrLen (&OptionString
[Index
])) {
1311 if (SkipValue
== 0) {
1314 // Since the Number of lines for this menu entry may or may not be reflected accurately
1315 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1316 // some testing to ensure we are keeping this in-sync.
1318 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1320 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1326 gBS
->FreePool (OutputString
);
1327 if (SkipValue
!= 0) {
1335 *OptionalString
= OptionString
;
1338 // Search table for UiDisplayMenu()
1340 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
1342 { SCAN_DOWN
, UiDown
},
1343 { SCAN_PAGE_UP
, UiPageUp
},
1344 { SCAN_PAGE_DOWN
, UiPageDown
},
1345 { SCAN_ESC
, UiReset
},
1346 { SCAN_F2
, UiPrevious
},
1347 { SCAN_LEFT
, UiLeft
},
1348 { SCAN_RIGHT
, UiRight
},
1349 { SCAN_F9
, UiDefault
},
1350 { SCAN_F10
, UiSave
}
1353 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
1354 { UiNoOperation
, CfUiNoOperation
},
1355 { UiDefault
, CfUiDefault
},
1356 { UiSelect
, CfUiSelect
},
1358 { UiDown
, CfUiDown
},
1359 { UiLeft
, CfUiLeft
},
1360 { UiRight
, CfUiRight
},
1361 { UiReset
, CfUiReset
},
1362 { UiSave
, CfUiSave
},
1363 { UiPrevious
, CfUiPrevious
},
1364 { UiPageUp
, CfUiPageUp
},
1365 { UiPageDown
, CfUiPageDown
}
1371 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1372 OUT EFI_IFR_DATA_ARRAY
*PageData
1376 Routine Description:
1377 Display menu and wait for user to select one menu option, then return it.
1378 If AutoBoot is enabled, then if user doesn't select any option,
1379 after period of time, it will automatically return the first menu option.
1382 SubMenu - Indicate is sub menu.
1383 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
1384 PageData - A pointer to the EFI_IFR_DATA_ARRAY.
1387 Return the pointer of the menu which selected,
1388 otherwise return NULL.
1403 UINTN DataAndTimeLineNumberPad
;
1405 INT16 OriginalTimeOut
;
1409 CHAR16
*OptionString
;
1410 CHAR16
*OutputString
;
1411 CHAR16
*FormattedString
;
1418 UI_MENU_LIST
*UiMenuList
;
1422 LIST_ENTRY
*TopOfScreen
;
1423 LIST_ENTRY
*SavedListEntry
;
1424 UI_MENU_OPTION
*Selection
;
1425 UI_MENU_OPTION
*MenuOption
;
1426 UI_MENU_OPTION
*NextMenuOption
;
1427 UI_MENU_OPTION
*SavedMenuOption
;
1428 UI_MENU_OPTION
*PreviousMenuOption
;
1429 EFI_IFR_BINARY
*IfrBinary
;
1430 UI_CONTROL_FLAG ControlFlag
;
1431 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1432 EFI_FILE_FORM_TAGS
*FileFormTags
;
1433 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1434 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
1435 UI_SCREEN_OPERATION ScreenOperation
;
1436 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1437 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1438 EFI_HII_VARIABLE_PACK_LIST
*NvMapListHead
;
1439 EFI_HII_VARIABLE_PACK_LIST
*NvMapListNode
;
1443 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1445 VariableDefinition
= NULL
;
1446 Status
= EFI_SUCCESS
;
1447 FormattedString
= NULL
;
1448 OptionString
= NULL
;
1449 ScreenOperation
= UiNoOperation
;
1451 FormCallback
= NULL
;
1452 FileFormTags
= NULL
;
1453 OutputString
= NULL
;
1458 MenuRefreshEntry
= gMenuRefreshHead
;
1459 OldMenuRefreshEntry
= gMenuRefreshHead
;
1460 NextMenuOption
= NULL
;
1461 PreviousMenuOption
= NULL
;
1462 SavedMenuOption
= NULL
;
1467 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1469 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
1470 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1471 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1473 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1474 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1478 Col
= LocalScreen
.LeftColumn
;
1480 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1483 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1485 TopOfScreen
= Menu
.ForwardLink
;
1490 // Get user's selection
1493 NewPos
= Menu
.ForwardLink
;
1494 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1496 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1498 ControlFlag
= CfInitialization
;
1501 switch (ControlFlag
) {
1502 case CfInitialization
:
1503 ControlFlag
= CfCheckSelection
;
1504 if (gExitRequired
) {
1505 ScreenOperation
= UiReset
;
1506 ControlFlag
= CfScreenOperation
;
1507 } else if (gSaveRequired
) {
1508 ScreenOperation
= UiSave
;
1509 ControlFlag
= CfScreenOperation
;
1510 } else if (IsListEmpty (&Menu
)) {
1511 ControlFlag
= CfReadKey
;
1515 case CfCheckSelection
:
1516 if (Selection
!= NULL
) {
1517 ControlFlag
= CfExit
;
1519 ControlFlag
= CfRepaint
;
1522 FileFormTags
= FileFormTagsHead
;
1526 ControlFlag
= CfRefreshHighLight
;
1532 SavedMenuOption
= MenuOption
;
1541 LocalScreen
.LeftColumn
,
1542 LocalScreen
.RightColumn
,
1543 TopRow
- SCROLL_ARROW_HEIGHT
,
1544 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1545 FIELD_TEXT
| FIELD_BACKGROUND
1548 while (gMenuRefreshHead
!= NULL
) {
1549 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
1551 gBS
->FreePool (gMenuRefreshHead
);
1553 gMenuRefreshHead
= OldMenuRefreshEntry
;
1556 for (Link
= TopOfScreen
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1557 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1558 MenuOption
->Row
= Row
;
1560 MenuOption
->Col
= Col
;
1561 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1564 if (MenuOption
->ThisTag
->GrayOut
) {
1565 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1567 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1568 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1572 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1576 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1577 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1578 PrintStringAt (Col
, Row
, OutputString
);
1581 // If there is more string to process print on the next row and increment the Skip value
1583 if (StrLen (&MenuOption
->Description
[Index
])) {
1589 gBS
->FreePool (OutputString
);
1599 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1600 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1602 if (OptionString
!= NULL
) {
1603 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1604 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1607 // If leading spaces on OptionString - remove the spaces
1609 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1610 MenuOption
->OptCol
++;
1613 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1614 OptionString
[Count
] = OptionString
[Index
];
1618 OptionString
[Count
] = CHAR_NULL
;
1622 // If this is a date or time op-code and is used to reflect an RTC, register the op-code
1624 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1625 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
) &&
1626 (MenuOption
->ThisTag
->StorageStart
>= FileFormTags
->FormTags
.Tags
[0].NvDataSize
)) {
1628 if (gMenuRefreshHead
== NULL
) {
1629 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1630 ASSERT (MenuRefreshEntry
!= NULL
);
1631 MenuRefreshEntry
->MenuOption
= MenuOption
;
1632 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1633 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1634 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1635 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1636 gMenuRefreshHead
= MenuRefreshEntry
;
1639 // Advance to the last entry
1641 for (MenuRefreshEntry
= gMenuRefreshHead
;
1642 MenuRefreshEntry
->Next
!= NULL
;
1643 MenuRefreshEntry
= MenuRefreshEntry
->Next
1646 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1647 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1648 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1649 MenuRefreshEntry
->MenuOption
= MenuOption
;
1650 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1651 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1652 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1653 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1657 Width
= (UINT16
) gOptionBlockWidth
;
1661 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1662 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1663 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1666 // If there is more string to process print on the next row and increment the Skip value
1668 if (StrLen (&OptionString
[Index
])) {
1672 // Since the Number of lines for this menu entry may or may not be reflected accurately
1673 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1674 // some testing to ensure we are keeping this in-sync.
1676 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1678 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1684 gBS
->FreePool (OutputString
);
1694 // If this is a text op with secondary text information
1696 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
) && (MenuOption
->ThisTag
->TextTwo
!= 0)) {
1697 StringPtr
= GetToken (MenuOption
->ThisTag
->TextTwo
, MenuOption
->Handle
);
1699 Width
= (UINT16
) gOptionBlockWidth
;
1703 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1704 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1705 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1708 // If there is more string to process print on the next row and increment the Skip value
1710 if (StrLen (&StringPtr
[Index
])) {
1714 // Since the Number of lines for this menu entry may or may not be reflected accurately
1715 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1716 // some testing to ensure we are keeping this in-sync.
1718 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1720 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1726 gBS
->FreePool (OutputString
);
1733 gBS
->FreePool (StringPtr
);
1737 // For now, assume left-justified 72 width max setup entries
1739 PrintStringAt (Col
, Row
, MenuOption
->Description
);
1742 // Tracker 6210 - need to handle the bottom of the display
1744 if (MenuOption
->Skip
> 1) {
1745 Row
+= MenuOption
->Skip
- SkipValue
;
1748 Row
+= MenuOption
->Skip
;
1751 if (Row
> BottomRow
) {
1752 if (!ValueIsScroll (FALSE
, Link
)) {
1756 Row
= BottomRow
+ 1;
1761 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1766 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1768 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1769 TopRow
- SCROLL_ARROW_HEIGHT
,
1773 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1777 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1779 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1780 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1784 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1787 if (SavedMenuOption
!= NULL
) {
1788 MenuOption
= SavedMenuOption
;
1793 case CfRefreshHighLight
:
1794 ControlFlag
= CfUpdateHelpString
;
1796 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1797 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1799 SavedValue
= Repaint
;
1802 if (NewPos
!= NULL
) {
1803 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1805 if (gLastOpr
&& (gEntryNumber
!= -1)) {
1806 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1807 if (gEntryNumber
!= MenuOption
->EntryNumber
) {
1808 ScreenOperation
= UiDown
;
1809 ControlFlag
= CfScreenOperation
;
1816 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1817 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1818 if (OptionString
!= NULL
) {
1819 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1820 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1823 // If leading spaces on OptionString - remove the spaces
1825 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1828 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1829 OptionString
[Count
] = OptionString
[Index
];
1833 OptionString
[Count
] = CHAR_NULL
;
1836 Width
= (UINT16
) gOptionBlockWidth
;
1838 OriginalRow
= MenuOption
->Row
;
1840 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1841 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1842 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1845 // If there is more string to process print on the next row and increment the Skip value
1847 if (StrLen (&OptionString
[Index
])) {
1851 gBS
->FreePool (OutputString
);
1854 MenuOption
->Row
= OriginalRow
;
1857 if (MenuOption
->ThisTag
->GrayOut
) {
1858 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1860 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1861 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1865 OriginalRow
= MenuOption
->Row
;
1866 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1868 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1869 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1870 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1873 // If there is more string to process print on the next row and increment the Skip value
1875 if (StrLen (&MenuOption
->Description
[Index
])) {
1879 gBS
->FreePool (OutputString
);
1882 MenuOption
->Row
= OriginalRow
;
1883 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1887 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1888 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
1891 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1893 if ((gPriorMenuEntry
!= 0) && (MenuOption
->EntryNumber
!= gPriorMenuEntry
) && (NewPos
->ForwardLink
!= &Menu
)) {
1894 ScreenOperation
= UiDown
;
1895 ControlFlag
= CfScreenOperation
;
1898 gPriorMenuEntry
= 0;
1901 // This is only possible if we entered this page and the first menu option is
1902 // a "non-menu" item. In that case, force it UiDown
1904 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
1906 // If we previously hit an UP command and we are still sitting on a text operation
1907 // we must continue going up
1909 if (ScreenOperation
== UiUp
) {
1910 ControlFlag
= CfScreenOperation
;
1913 ScreenOperation
= UiDown
;
1914 ControlFlag
= CfScreenOperation
;
1919 // Set reverse attribute
1921 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
1922 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1925 // Assuming that we have a refresh linked-list created, lets annotate the
1926 // appropriate entry that we are highlighting with its new attribute. Just prior to this
1927 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
1929 if (gMenuRefreshHead
!= NULL
) {
1930 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
1931 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1932 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
1933 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
;
1939 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1940 if (OptionString
!= NULL
) {
1941 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1942 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1945 // If leading spaces on OptionString - remove the spaces
1947 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1950 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1951 OptionString
[Count
] = OptionString
[Index
];
1955 OptionString
[Count
] = CHAR_NULL
;
1957 Width
= (UINT16
) gOptionBlockWidth
;
1959 OriginalRow
= MenuOption
->Row
;
1961 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1962 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1963 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1966 // If there is more string to process print on the next row and increment the Skip value
1968 if (StrLen (&OptionString
[Index
])) {
1972 gBS
->FreePool (OutputString
);
1975 MenuOption
->Row
= OriginalRow
;
1978 OriginalRow
= MenuOption
->Row
;
1980 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1982 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1983 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1984 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1987 // If there is more string to process print on the next row and increment the Skip value
1989 if (StrLen (&MenuOption
->Description
[Index
])) {
1993 gBS
->FreePool (OutputString
);
1996 MenuOption
->Row
= OriginalRow
;
2001 if (((NewPos
->ForwardLink
!= &Menu
) && (ScreenOperation
== UiDown
)) ||
2002 ((NewPos
->BackLink
!= &Menu
) && (ScreenOperation
== UiUp
)) ||
2003 (ScreenOperation
== UiNoOperation
)
2005 UpdateKeyHelp (MenuOption
, FALSE
);
2008 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2011 // Clear reverse attribute
2013 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2016 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2017 // if we didn't break halfway when process CfRefreshHighLight.
2019 Repaint
= SavedValue
;
2022 case CfUpdateHelpString
:
2023 ControlFlag
= CfPrepareToReadKey
;
2026 (Repaint
|| NewLine
||
2027 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2028 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) &&
2029 !(gClassOfVfr
== EFI_GENERAL_APPLICATION_SUBCLASS
)) {
2031 // Don't print anything if it is a NULL help token
2033 if (MenuOption
->ThisTag
->Help
== 0x00000000) {
2034 StringPtr
= (CHAR16
*) L
"\0";
2036 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2039 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2041 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2043 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2045 // Pad String with spaces to simulate a clearing of the previous line
2047 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2048 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], (CHAR16
*) L
" ");
2052 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2054 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2059 // Reset this flag every time we finish using it.
2065 case CfPrepareToReadKey
:
2066 ControlFlag
= CfReadKey
;
2068 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
2069 FileFormTags
= FileFormTags
->NextFile
;
2072 ScreenOperation
= UiNoOperation
;
2074 Status
= gBS
->HandleProtocol (
2075 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
2076 &gEfiFormCallbackProtocolGuid
,
2077 (VOID
**) &FormCallback
2083 ControlFlag
= CfScreenOperation
;
2085 OriginalTimeOut
= FrontPageTimeOutValue
;
2087 if (FrontPageTimeOutValue
>= 0 && (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) && FrontPageTimeOutValue
!= (INT16
) -1) {
2089 // Remember that if set to 0, must immediately boot an option
2091 if (FrontPageTimeOutValue
== 0) {
2092 FrontPageTimeOutValue
= 0xFFFF;
2093 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2094 if (EFI_ERROR (Status
)) {
2095 Status
= EFI_TIMEOUT
;
2100 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, ONE_SECOND
);
2101 if (Status
== EFI_TIMEOUT
) {
2102 EFI_IFR_DATA_ENTRY
*DataEntry
;
2104 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
2106 PageData
->EntryCount
= 1;
2107 Count
= (UINT32
) ((OriginalTimeOut
- FrontPageTimeOutValue
) * 100 / OriginalTimeOut
);
2108 CopyMem (&DataEntry
->Data
, &Count
, sizeof (UINT32
));
2110 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2111 FormCallback
->Callback (
2114 (EFI_IFR_DATA_ARRAY
*) PageData
,
2119 // Count down 1 second
2121 FrontPageTimeOutValue
--;
2124 ASSERT (!EFI_ERROR (Status
));
2125 PageData
->EntryCount
= 0;
2126 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2127 FormCallback
->Callback (
2130 (EFI_IFR_DATA_ARRAY
*) PageData
,
2135 FrontPageTimeOutValue
= 0xFFFF;
2139 // Wait for user's selection, no auto boot
2141 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
2143 } while (Status
== EFI_TIMEOUT
);
2147 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2148 DisableQuietBoot ();
2151 if (Status
== EFI_TIMEOUT
) {
2152 Key
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
2154 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2156 // if we encounter error, continue to read another key in.
2158 if (EFI_ERROR (Status
)) {
2159 ControlFlag
= CfReadKey
;
2164 switch (Key
.UnicodeChar
) {
2165 case CHAR_CARRIAGE_RETURN
:
2166 Selection
= MenuOption
;
2167 ScreenOperation
= UiSelect
;
2172 // We will push the adjustment of these numeric values directly to the input handler
2176 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2178 if (Key
.UnicodeChar
== '+') {
2179 gDirection
= SCAN_RIGHT
;
2181 gDirection
= SCAN_LEFT
;
2184 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, NULL
, &OptionString
);
2189 ScreenOperation
= UiUp
;
2194 ScreenOperation
= UiDown
;
2198 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
2200 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !(MenuOption
->ThisTag
->GrayOut
)) {
2201 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2202 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2203 Selection
= MenuOption
;
2204 ScreenOperation
= UiSelect
;
2211 if (((Key
.ScanCode
== SCAN_F1
) && ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
)) ||
2212 ((Key
.ScanCode
== SCAN_F2
) && ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
)) ||
2213 ((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2214 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2217 // If the function key has been disabled, just ignore the key.
2220 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2221 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2222 if ((Key
.ScanCode
== SCAN_F9
) || (Key
.ScanCode
== SCAN_F10
)) {
2224 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2227 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2236 case CfScreenOperation
:
2237 IfrBinary
= gBinaryDataHead
;
2240 // Advance to the Ifr we are using
2242 for (Index
= 0; Index
< gActiveIfr
; Index
++) {
2243 IfrBinary
= IfrBinary
->Next
;
2246 if (ScreenOperation
!= UiPrevious
&& ScreenOperation
!= UiReset
) {
2248 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2249 // ignore the selection and go back to reading keys.
2251 if (IsListEmpty (&Menu
)) {
2252 ControlFlag
= CfReadKey
;
2256 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2258 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
2259 NextMenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2260 if (!(NextMenuOption
->ThisTag
->GrayOut
) && (NextMenuOption
->ThisTag
->Operand
!= EFI_IFR_SUBTITLE_OP
)) {
2265 if (Link
== &Menu
) {
2266 ControlFlag
= CfPrepareToReadKey
;
2272 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2275 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2276 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2283 ControlFlag
= CfCheckSelection
;
2285 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2287 if (MenuOption
!= NULL
) {
2288 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2295 if (IsListEmpty (&gMenuList
)) {
2297 if (IsListEmpty (&Menu
)) {
2298 ControlFlag
= CfReadKey
;
2305 while (gMenuRefreshHead
!= NULL
) {
2306 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
2308 gBS
->FreePool (gMenuRefreshHead
);
2310 gMenuRefreshHead
= OldMenuRefreshEntry
;
2313 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
2316 UiRemoveMenuListEntry (MenuOption
, &Selection
);
2317 Selection
->Previous
= TRUE
;
2322 gActiveIfr
= Selection
->IfrNumber
;
2326 ControlFlag
= CfCheckSelection
;
2328 ExtractRequestedNvMap (FileFormTags
, MenuOption
->ThisTag
->VariableNumber
, &VariableDefinition
);
2331 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
&&
2332 !(MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
)) ||
2333 (MenuOption
->ThisTag
->GrayOut
) ||
2334 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2335 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2341 UpdateKeyHelp (MenuOption
, TRUE
);
2342 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, PageData
, &OptionString
);
2344 if (EFI_ERROR (Status
)) {
2350 if (OptionString
!= NULL
) {
2351 PrintStringAt (LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ 1, MenuOption
->Row
, OptionString
);
2354 if (MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
2355 Selection
= MenuOption
;
2358 if (Selection
== NULL
) {
2362 Location
= (UINT8
*) &PageData
->EntryCount
;
2365 // If not a goto, dump single piece of data, otherwise dump everything
2367 if (Selection
->ThisTag
->Operand
== EFI_IFR_REF_OP
) {
2369 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2371 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2377 UiAddMenuListEntry (Selection
);
2378 gPriorMenuEntry
= 0;
2381 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
2383 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
2384 UiMenuList
->FormerEntryNumber
= MenuOption
->EntryNumber
;
2389 // Rewind to the beginning of the menu
2391 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2395 // Get Total Count of Menu entries
2397 for (Count
= 1; NewPos
->ForwardLink
!= &Menu
; NewPos
= NewPos
->ForwardLink
) {
2401 // Rewind to the beginning of the menu
2403 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2407 // Copy the number of entries being described to the PageData location
2409 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2411 for (Index
= 4; NewPos
->ForwardLink
!= &Menu
; Index
= Index
+ MenuOption
->ThisTag
->StorageWidth
+ 2) {
2413 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2414 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2415 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2417 &Location
[Index
+ 4],
2418 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2419 MenuOption
->ThisTag
->StorageWidth
2421 NewPos
= NewPos
->ForwardLink
;
2425 gPriorMenuEntry
= MenuOption
->EntryNumber
;
2430 // Copy the number of entries being described to the PageData location
2432 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2435 // Start at PageData[4] since the EntryCount is a UINT32
2440 // Copy data to destination
2442 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2443 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2445 &Location
[Index
+ 4],
2446 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2447 MenuOption
->ThisTag
->StorageWidth
2454 ControlFlag
= CfCheckSelection
;
2456 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
2460 // If NV flag is up, prompt user
2462 if (gNvUpdateRequired
) {
2463 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2465 YesResponse
= gYesResponse
[0];
2466 NoResponse
= gNoResponse
[0];
2469 CreateDialog (3, TRUE
, 0, NULL
, &Key
, gEmptyString
, gAreYouSure
, gEmptyString
);
2472 (Key
.ScanCode
!= SCAN_ESC
) &&
2473 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2474 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2478 // If the user hits the YesResponse key
2480 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2488 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2490 if (MenuOption
!= NULL
) {
2491 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2499 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2500 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
2504 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2508 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2509 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2511 if (IfrBinary
->UnRegisterOnExit
) {
2512 Hii
->RemovePack (Hii
, MenuOption
->Handle
);
2518 // Clean up the allocated data buffers
2520 FreeData (FileFormTagsHead
, FormattedString
, OptionString
);
2522 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2526 ControlFlag
= CfCheckSelection
;
2527 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2528 if (MenuOption
->Skip
== 1) {
2530 // In the tail of the Date/Time op-code set, go left.
2532 NewPos
= NewPos
->BackLink
;
2535 // In the middle of the Data/Time op-code set, go left.
2537 NextMenuOption
= CR (NewPos
->ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2538 if (NextMenuOption
->Skip
== 1) {
2539 NewPos
= NewPos
->BackLink
;
2546 ControlFlag
= CfCheckSelection
;
2547 if ((MenuOption
->Skip
== 0) &&
2548 ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
))
2551 // We are in the head or middle of the Date/Time op-code set, advance right.
2553 NewPos
= NewPos
->ForwardLink
;
2558 ControlFlag
= CfCheckSelection
;
2560 if (NewPos
->BackLink
!= &Menu
) {
2563 // Adjust Date/Time position before we advance forward.
2565 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2568 // Caution that we have already rewind to the top, don't go backward in this situation.
2570 if (NewPos
->BackLink
!= &Menu
) {
2571 NewPos
= NewPos
->BackLink
;
2574 PreviousMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2577 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2578 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2579 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2580 // checking can be done.
2582 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2586 // If the previous MenuOption contains a display-only op-code, skip to the next one
2588 if (PreviousMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| PreviousMenuOption
->ThisTag
->GrayOut
) {
2590 // This is ok as long as not at the end of the list
2592 if (NewPos
->BackLink
== &Menu
) {
2594 // If we are at the start of the list, then this list must start with a display only
2595 // piece of data, so do not allow the backward motion
2597 ScreenOperation
= UiDown
;
2599 if (PreviousMenuOption
->Row
<= TopRow
) {
2600 if (TopOfScreen
->BackLink
!= &Menu
) {
2601 TopOfScreen
= TopOfScreen
->BackLink
;
2606 UpdateStatusBar (INPUT_ERROR
, PreviousMenuOption
->ThisTag
->Flags
, FALSE
);
2612 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2613 // don't worry about a redraw.
2615 if ((MenuOption
->Row
- PreviousMenuOption
->Skip
- DataAndTimeLineNumberPad
< TopRow
) ||
2616 (PreviousMenuOption
->Skip
> MenuOption
->Row
)
2619 if (TopOfScreen
->BackLink
== &Menu
) {
2626 // Is the current top of screen a zero-advance op-code?
2627 // If so, keep moving forward till we hit a >0 advance op-code
2629 SavedMenuOption
= CR (TopOfScreen
->BackLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2630 TopOfScreen
= TopOfScreen
->BackLink
;
2631 } while (SavedMenuOption
->Skip
== 0);
2633 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2635 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2638 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2641 SavedMenuOption
= MenuOption
;
2642 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2643 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2645 // If we are at the end of the list and sitting on a text op, we need to more forward
2647 ScreenOperation
= UiDown
;
2648 ControlFlag
= CfScreenOperation
;
2652 MenuOption
= SavedMenuOption
;
2658 ControlFlag
= CfCheckSelection
;
2660 SavedListEntry
= NewPos
;
2662 for (Index
= BottomRow
; Index
>= TopRow
+ 1; Index
-= MenuOption
->Skip
) {
2663 if (Link
->BackLink
== &Menu
) {
2665 Link
= SavedListEntry
;
2666 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2672 Link
= Link
->BackLink
;
2673 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2675 SavedListEntry
= Link
;
2681 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2682 // Don't do this when we are already in the first page.
2685 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2686 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2687 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2692 ControlFlag
= CfCheckSelection
;
2694 SavedListEntry
= NewPos
;
2696 NewPos
= TopOfScreen
;
2697 for (Index
= TopRow
; Index
<= BottomRow
- 1; Index
+= MenuOption
->Skip
) {
2698 if (NewPos
->ForwardLink
== &Menu
) {
2699 NewPos
= SavedListEntry
;
2700 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2709 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2710 NewPos
= NewPos
->ForwardLink
;
2717 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2718 // Don't do this when we are already in the last page.
2721 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2722 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2723 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2728 ControlFlag
= CfCheckSelection
;
2730 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2731 // to be one that progresses to the next set of op-codes, we need to advance to the last
2732 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2733 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2734 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2735 // the Date/Time op-code.
2737 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2739 if (NewPos
->ForwardLink
!= &Menu
) {
2741 NewPos
= NewPos
->ForwardLink
;
2742 NextMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2746 // If the next MenuOption contains a display-only op-code, skip to the next one
2747 // Also if the next MenuOption is date or time,
2749 if (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| NextMenuOption
->ThisTag
->GrayOut
) {
2751 // This is ok as long as not at the end of the list
2753 if (NewPos
== &Menu
) {
2755 // If we are at the end of the list, then this list must end with a display only
2756 // piece of data, so do not allow the forward motion
2758 UpdateStatusBar (INPUT_ERROR
, NextMenuOption
->ThisTag
->Flags
, FALSE
);
2759 NewPos
= NewPos
->BackLink
;
2760 ScreenOperation
= UiUp
;
2766 // An option might be multi-line, so we need to reflect that data in the overall skip value
2768 UpdateOptionSkipLines (PageData
, NextMenuOption
, FileFormTagsHead
, &OptionString
, SkipValue
);
2770 if (NextMenuOption
->Skip
> 1) {
2771 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ NextMenuOption
->Skip
- 1;
2773 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DataAndTimeLineNumberPad
;
2776 // If we are going to scroll
2778 if (Temp
> BottomRow
) {
2781 // Is the current top of screen a zero-advance op-code?
2782 // If so, keep moving forward till we hit a >0 advance op-code
2784 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2787 // If bottom op-code is more than one line or top op-code is more than one line
2789 if ((NextMenuOption
->Skip
> 1) || (MenuOption
->Skip
> 1)) {
2791 // Is the bottom op-code greater than or equal in size to the top op-code?
2793 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
2795 // Skip the top op-code
2797 TopOfScreen
= TopOfScreen
->ForwardLink
;
2798 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
2800 OldSkipValue
= Difference
;
2802 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2805 // If we have a remainder, skip that many more op-codes until we drain the remainder
2808 Difference
>= (INTN
) SavedMenuOption
->Skip
;
2809 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
2812 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2814 TopOfScreen
= TopOfScreen
->ForwardLink
;
2815 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2816 if (Difference
< (INTN
) SavedMenuOption
->Skip
) {
2817 Difference
= SavedMenuOption
->Skip
- Difference
- 1;
2820 if (Difference
== (INTN
) SavedMenuOption
->Skip
) {
2821 TopOfScreen
= TopOfScreen
->ForwardLink
;
2822 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2823 Difference
= SavedMenuOption
->Skip
- Difference
;
2829 // Since we will act on this op-code in the next routine, and increment the
2830 // SkipValue, set the skips to one less than what is required.
2832 SkipValue
= Difference
- 1;
2836 // Since we will act on this op-code in the next routine, and increment the
2837 // SkipValue, set the skips to one less than what is required.
2839 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
2842 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2843 TopOfScreen
= TopOfScreen
->ForwardLink
;
2846 SkipValue
= OldSkipValue
;
2850 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2851 // Let's set a skip flag to smoothly scroll the top of the screen.
2853 if (SavedMenuOption
->Skip
> 1) {
2854 if (SavedMenuOption
== NextMenuOption
) {
2861 TopOfScreen
= TopOfScreen
->ForwardLink
;
2863 } while (SavedMenuOption
->Skip
== 0);
2866 OldSkipValue
= SkipValue
;
2869 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2873 SavedMenuOption
= MenuOption
;
2874 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2875 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2877 // If we are at the end of the list and sitting on a text op, we need to more forward
2879 ScreenOperation
= UiUp
;
2880 ControlFlag
= CfScreenOperation
;
2884 MenuOption
= SavedMenuOption
;
2886 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2888 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2894 ControlFlag
= CfCheckSelection
;
2896 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2898 if (MenuOption
!= NULL
) {
2899 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2906 // If callbacks are active, and the callback has a Write method, try to use it
2908 if (FileFormTags
->VariableDefinitions
->VariableName
== NULL
) {
2909 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2910 Status
= FormCallback
->NvWrite (
2912 (CHAR16
*) L
"Setup",
2913 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2914 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2915 VariableDefinition
->VariableSize
,
2916 (VOID
*) VariableDefinition
->NvRamMap
,
2921 Status
= gRT
->SetVariable (
2922 (CHAR16
*) L
"Setup",
2923 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2924 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2925 VariableDefinition
->VariableSize
,
2926 (VOID
*) VariableDefinition
->NvRamMap
2930 VariableDefinition
= FileFormTags
->VariableDefinitions
;
2932 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
2933 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2934 Status
= FormCallback
->NvWrite (
2936 VariableDefinition
->VariableName
,
2937 &VariableDefinition
->Guid
,
2938 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2939 VariableDefinition
->VariableSize
,
2940 (VOID
*) VariableDefinition
->NvRamMap
,
2945 Status
= gRT
->SetVariable (
2946 VariableDefinition
->VariableName
,
2947 &VariableDefinition
->Guid
,
2948 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2949 VariableDefinition
->VariableSize
,
2950 (VOID
*) VariableDefinition
->NvRamMap
2956 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2957 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2961 ControlFlag
= CfCheckSelection
;
2963 NvMapListHead
= NULL
;
2965 Status
= Hii
->GetDefaultImage (Hii
, MenuOption
->Handle
, EFI_IFR_FLAG_DEFAULT
, &NvMapListHead
);
2967 if (!EFI_ERROR (Status
)) {
2968 ASSERT_EFI_ERROR (NULL
!= NvMapListHead
);
2970 NvMapListNode
= NvMapListHead
;
2972 while (NULL
!= NvMapListNode
) {
2973 if (FileFormTags
->VariableDefinitions
->VariableId
== NvMapListNode
->VariablePack
->VariableId
) {
2974 NvMap
= (VOID
*) ((CHAR8
*) NvMapListNode
->VariablePack
+ sizeof (EFI_HII_VARIABLE_PACK
) + NvMapListNode
->VariablePack
->VariableNameLength
);
2975 NvMapSize
= NvMapListNode
->VariablePack
->Header
.Length
- sizeof (EFI_HII_VARIABLE_PACK
) - NvMapListNode
->VariablePack
->VariableNameLength
;
2978 NvMapListNode
= NvMapListNode
->NextVariablePack
;
2982 // Free the buffer that was allocated.
2984 gBS
->FreePool (FileFormTags
->VariableDefinitions
->NvRamMap
);
2985 gBS
->FreePool (FileFormTags
->VariableDefinitions
->FakeNvRamMap
);
2988 // Allocate, copy the NvRamMap.
2990 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
- FileFormTags
->VariableDefinitions
->VariableSize
);
2991 FileFormTags
->VariableDefinitions
->VariableSize
= (UINT16
) NvMapSize
;
2992 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
+ FileFormTags
->VariableDefinitions
->VariableSize
);
2994 FileFormTags
->VariableDefinitions
->NvRamMap
= AllocateZeroPool (FileFormTags
->VariableDefinitions
->VariableSize
);
2995 ASSERT (FileFormTags
->VariableDefinitions
->NvRamMap
!= NULL
);
2997 FileFormTags
->VariableDefinitions
->FakeNvRamMap
= AllocateZeroPool (NvMapSize
+ FileFormTags
->VariableDefinitions
->VariableFakeSize
);
2998 ASSERT (FileFormTags
->VariableDefinitions
->FakeNvRamMap
!= NULL
);
3000 CopyMem (FileFormTags
->VariableDefinitions
->NvRamMap
, NvMap
, NvMapSize
);
3001 gBS
->FreePool (NvMapListHead
);
3004 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, TRUE
);
3007 // After the repaint operation, we should refresh the highlight.
3012 case CfUiNoOperation
:
3013 ControlFlag
= CfCheckSelection
;
3017 while (gMenuRefreshHead
!= NULL
) {
3018 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
3020 gBS
->FreePool (gMenuRefreshHead
);
3022 gMenuRefreshHead
= OldMenuRefreshEntry
;
3025 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3026 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3027 gST
->ConOut
->OutputString (gST
->ConOut
, (CHAR16
*) L
"\n");
3029 gActiveIfr
= MenuOption
->IfrNumber
;
3040 IN BOOLEAN Direction
,
3041 IN LIST_ENTRY
*CurrentPos
3045 Routine Description:
3046 Determine if the menu is the last menu that can be selected.
3049 Direction - the scroll direction. False is down. True is up.
3052 FALSE -- the menu isn't the last menu that can be selected.
3053 TRUE -- the menu is the last menu that can be selected.
3057 UI_MENU_OPTION
*MenuOption
;
3060 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
3062 if (Temp
== &Menu
) {
3066 for (; Temp
!= &Menu
; Temp
= Direction
? Temp
->BackLink
: Temp
->ForwardLink
) {
3067 MenuOption
= CR (Temp
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3068 if (!(MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
)) {
3077 AdjustDateAndTimePosition (
3078 IN BOOLEAN DirectionUp
,
3079 IN LIST_ENTRY
**CurrentPosition
3082 Routine Description:
3083 Adjust Data and Time tag position accordingly.
3084 Data format : [01/02/2004] [11:22:33]
3085 Line number : 0 0 1 0 0 1
3088 Direction - the up or down direction. False is down. True is up.
3089 CurrentPos - Current position.
3092 Return line number to pad. It is possible that we stand on a zero-advance
3093 data or time opcode, so pad one line when we judge if we are going to scroll outside.
3097 LIST_ENTRY
*NewPosition
;
3098 UI_MENU_OPTION
*MenuOption
;
3099 UINTN PadLineNumber
;
3102 NewPosition
= *CurrentPosition
;
3103 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3105 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3107 // Calculate the distance from current position to the last Date/Time op-code.
3110 while (MenuOption
->ThisTag
->NumberOfLines
== 0) {
3112 NewPosition
= NewPosition
->ForwardLink
;
3113 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3117 NewPosition
= *CurrentPosition
;
3120 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
3121 // to be one that back to the previous set of op-codes, we need to advance to the first
3122 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate
3123 // checking can be done.
3125 while (Count
++ < 2) {
3126 NewPosition
= NewPosition
->BackLink
;
3130 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3131 // to be one that progresses to the next set of op-codes, we need to advance to the last
3132 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate
3133 // checking can be done.
3135 while (Count
-- > 0) {
3136 NewPosition
= NewPosition
->ForwardLink
;
3140 *CurrentPosition
= NewPosition
;
3143 return PadLineNumber
;