3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation for UI.
41 Set Buffer to Value for Size bytes.
45 Buffer - Memory to set.
47 Size - Number of bytes to set
49 Value - Value of the set operation.
72 Initialize Menu option list.
80 InitializeListHead (&Menu
);
90 Initialize Menu option list.
98 InitializeListHead (&gMenuList
);
102 UiRemoveMenuListEntry (
103 IN UI_MENU_OPTION
*Selection
,
104 OUT UI_MENU_OPTION
**PreviousSelection
109 Remove Menu option list.
117 UI_MENU_LIST
*UiMenuList
;
119 *PreviousSelection
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
120 ASSERT (*PreviousSelection
!= NULL
);
122 if (!IsListEmpty (&gMenuList
)) {
123 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
124 (*PreviousSelection
)->IfrNumber
= UiMenuList
->Selection
.IfrNumber
;
125 (*PreviousSelection
)->FormId
= UiMenuList
->Selection
.FormId
;
126 (*PreviousSelection
)->Tags
= UiMenuList
->Selection
.Tags
;
127 (*PreviousSelection
)->ThisTag
= UiMenuList
->Selection
.ThisTag
;
128 (*PreviousSelection
)->Handle
= UiMenuList
->Selection
.Handle
;
129 gEntryNumber
= UiMenuList
->FormerEntryNumber
;
130 RemoveEntryList (&UiMenuList
->MenuLink
);
131 gBS
->FreePool (UiMenuList
);
142 Free Menu option linked list.
150 UI_MENU_LIST
*UiMenuList
;
152 while (!IsListEmpty (&gMenuList
)) {
153 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
154 RemoveEntryList (&UiMenuList
->MenuLink
);
155 gBS
->FreePool (UiMenuList
);
161 IN UI_MENU_OPTION
*Selection
166 Add one menu entry to the linked lst
174 UI_MENU_LIST
*UiMenuList
;
176 UiMenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
177 ASSERT (UiMenuList
!= NULL
);
179 UiMenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
180 CopyMem (&UiMenuList
->Selection
, Selection
, sizeof (UI_MENU_OPTION
));
182 InsertHeadList (&gMenuList
, &UiMenuList
->MenuLink
);
192 Free Menu option linked list.
200 UI_MENU_OPTION
*MenuOption
;
202 while (!IsListEmpty (&Menu
)) {
203 MenuOption
= CR (Menu
.ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
204 RemoveEntryList (&MenuOption
->Link
);
207 // We allocated space for this description when we did a GetToken, free it here
209 gBS
->FreePool (MenuOption
->Description
);
210 gBS
->FreePool (MenuOption
);
222 Refresh screen with current date and/or time based on screen context
230 CHAR16
*OptionString
;
231 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
237 if (gMenuRefreshHead
!= NULL
) {
239 MenuRefreshEntry
= gMenuRefreshHead
;
242 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
243 ProcessOptions (MenuRefreshEntry
->MenuOption
, FALSE
, MenuRefreshEntry
->FileFormTagsHead
, NULL
, &OptionString
);
245 if (OptionString
!= NULL
) {
247 // If leading spaces on OptionString - remove the spaces
249 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
252 for (Loop
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
253 OptionString
[Loop
] = OptionString
[Index
];
257 OptionString
[Loop
] = CHAR_NULL
;
259 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, OptionString
);
262 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
264 } while (MenuRefreshEntry
!= NULL
);
267 if (OptionString
!= NULL
) {
268 gBS
->FreePool (OptionString
);
273 UiWaitForSingleEvent (
275 IN UINT64 Timeout OPTIONAL
280 Wait for a given event to fire, or for an optional timeout to expire.
283 Event - The event to wait for
285 Timeout - An optional timeout value in 100 ns units.
289 EFI_SUCCESS - Event fired before Timeout expired.
290 EFI_TIME_OUT - Timout expired before Event fired.
296 EFI_EVENT TimerEvent
;
297 EFI_EVENT WaitList
[2];
301 // Create a timer event
303 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
304 if (!EFI_ERROR (Status
)) {
306 // Set the timer event
315 // Wait for the original event or the timer
318 WaitList
[1] = TimerEvent
;
319 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
320 gBS
->CloseEvent (TimerEvent
);
323 // If the timer expired, change the return to timed out
325 if (!EFI_ERROR (Status
) && Index
== 1) {
326 Status
= EFI_TIMEOUT
;
331 // Update screen every second
333 Timeout
= ONE_SECOND
;
336 Status
= gBS
->CreateEvent (EFI_EVENT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
339 // Set the timer event
348 // Wait for the original event or the timer
351 WaitList
[1] = TimerEvent
;
352 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
355 // If the timer expired, update anything that needs a refresh and keep waiting
357 if (!EFI_ERROR (Status
) && Index
== 1) {
358 Status
= EFI_TIMEOUT
;
359 UpdateDateAndTime ();
362 gBS
->CloseEvent (TimerEvent
);
363 } while (Status
== EFI_TIMEOUT
);
372 IN EFI_HII_HANDLE Handle
,
380 Add one menu option by specified description and context.
383 String - String description for this option.
384 Context - Context data for entry.
390 UI_MENU_OPTION
*MenuOption
;
392 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
395 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
396 MenuOption
->Description
= String
;
397 MenuOption
->Handle
= Handle
;
398 MenuOption
->FormBinary
= FormBinary
;
399 MenuOption
->IfrNumber
= IfrNumber
;
400 MenuOption
->Skip
= 1;
401 MenuOption
->Tags
= Tags
;
402 MenuOption
->TagIndex
= 0;
403 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
404 MenuOption
->EntryNumber
= (UINT16
) IfrNumber
;
406 InsertTailList (&Menu
, &MenuOption
->Link
);
412 IN EFI_HII_HANDLE Handle
,
416 IN UINT16 MenuItemCount
421 Add one menu option by specified description and context.
424 String - String description for this option.
425 Context - Context data for entry.
431 UI_MENU_OPTION
*MenuOption
;
433 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
436 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
437 MenuOption
->Description
= String
;
438 MenuOption
->Handle
= Handle
;
439 MenuOption
->Skip
= Tags
[TagIndex
].NumberOfLines
;
440 MenuOption
->IfrNumber
= gActiveIfr
;
441 MenuOption
->Tags
= Tags
;
442 MenuOption
->TagIndex
= TagIndex
;
443 MenuOption
->ThisTag
= &(MenuOption
->Tags
[MenuOption
->TagIndex
]);
444 MenuOption
->Consistency
= Tags
[TagIndex
].Consistency
;
445 MenuOption
->FormId
= FormId
;
446 MenuOption
->GrayOut
= Tags
[TagIndex
].GrayOut
;
447 MenuOption
->EntryNumber
= MenuItemCount
;
449 InsertTailList (&Menu
, &MenuOption
->Link
);
454 IN UINTN NumberOfLines
,
456 IN UINTN MaximumStringSize
,
457 OUT CHAR16
*StringBuffer
,
458 OUT EFI_INPUT_KEY
*KeyValue
,
465 Routine used to abstract a generic dialog interface and return the selected key or string
468 NumberOfLines - The number of lines for the dialog box
469 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue
470 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and
471 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns
472 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes
473 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE
474 KeyValue - The EFI_KEY value returned if HotKey is TRUE..
475 String - Pointer to the first string in the list
476 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box
479 EFI_SUCCESS - Displayed dialog and received user interaction
480 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))
481 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine
490 CHAR16
*BufferedString
;
496 BOOLEAN SelectionComplete
;
498 UINTN CurrentAttribute
;
499 UINTN DimensionsWidth
;
500 UINTN DimensionsHeight
;
502 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
503 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
505 SelectionComplete
= FALSE
;
507 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
508 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
509 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
512 ASSERT (BufferedString
);
514 VA_START (Marker
, String
);
517 // Zero the outgoing buffer
519 ZeroMem (StringBuffer
, MaximumStringSize
);
522 if (KeyValue
== NULL
) {
523 return EFI_INVALID_PARAMETER
;
526 if (StringBuffer
== NULL
) {
527 return EFI_INVALID_PARAMETER
;
533 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
535 LargestString
= (GetStringWidth (String
) / 2);
537 if (LargestString
== L
' ') {
541 // Determine the largest string in the dialog box
542 // Notice we are starting with 1 since String is the first string
544 for (Count
= 1; Count
< NumberOfLines
; Count
++) {
545 StackString
= VA_ARG (Marker
, CHAR16
*);
547 if (StackString
[0] == L
' ') {
548 InputOffset
= Count
+ 1;
551 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
553 // Size of the string visually and subtract the width by one for the null-terminator
555 LargestString
= (GetStringWidth (StackString
) / 2);
559 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
560 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
567 CreateSharedPopUp (LargestString
, NumberOfLines
, &String
);
570 // Take the first key typed and report it back?
573 WaitForKeyStroke (&Key
);
574 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
578 WaitForKeyStroke (&Key
);
580 switch (Key
.UnicodeChar
) {
582 switch (Key
.ScanCode
) {
584 gBS
->FreePool (TempString
);
585 gBS
->FreePool (BufferedString
);
586 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
587 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
588 return EFI_DEVICE_ERROR
;
596 case CHAR_CARRIAGE_RETURN
:
597 SelectionComplete
= TRUE
;
598 gBS
->FreePool (TempString
);
599 gBS
->FreePool (BufferedString
);
600 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
601 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
606 if (StringBuffer
[0] != CHAR_NULL
) {
607 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
608 TempString
[Index
] = StringBuffer
[Index
];
611 // Effectively truncate string by 1 character
613 TempString
[Index
- 1] = CHAR_NULL
;
614 StrCpy (StringBuffer
, TempString
);
619 // If it is the beginning of the string, don't worry about checking maximum limits
621 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
622 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
623 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
624 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
625 KeyPad
[0] = Key
.UnicodeChar
;
626 KeyPad
[1] = CHAR_NULL
;
627 StrCat (StringBuffer
, KeyPad
);
628 StrCat (TempString
, KeyPad
);
631 // If the width of the input string is now larger than the screen, we nee to
632 // adjust the index to start printing portions of the string
634 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
636 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
638 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
639 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
644 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
645 BufferedString
[Count
] = StringBuffer
[Index
];
648 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
651 } while (!SelectionComplete
);
654 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
655 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
661 IN UINTN RequestedWidth
,
662 IN UINTN NumberOfLines
,
663 IN CHAR16
**ArrayOfStrings
675 UINTN DimensionsWidth
;
676 UINTN DimensionsHeight
;
678 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
679 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
683 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
685 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
686 RequestedWidth
= DimensionsWidth
- 2;
689 // Subtract the PopUp width from total Columns, allow for one space extra on
690 // each end plus a border.
692 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
693 End
= Start
+ RequestedWidth
+ 1;
695 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
696 Bottom
= Top
+ NumberOfLines
+ 2;
698 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
699 PrintCharAt (Start
, Top
, Character
);
700 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
701 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
702 PrintChar (Character
);
705 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
706 PrintChar (Character
);
707 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
708 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++) {
709 String
= ArrayOfStrings
[Count
];
713 // This will clear the background of the line - we never know who might have been
714 // here before us. This differs from the next clear in that it used the non-reverse
715 // video for normal printing.
717 if (GetStringWidth (String
) / 2 > 1) {
718 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
721 // Passing in a space results in the assumption that this is where typing will occur
723 if (String
[0] == L
' ') {
724 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
727 // Passing in a NULL results in a blank space
729 if (String
[0] == CHAR_NULL
) {
730 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
734 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
738 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
739 PrintCharAt (Start
, Index
+ 1, Character
);
740 PrintCharAt (End
- 1, Index
+ 1, Character
);
743 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
744 PrintCharAt (Start
, Bottom
- 1, Character
);
745 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
746 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
747 PrintChar (Character
);
750 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
751 PrintChar (Character
);
756 IN UINTN RequestedWidth
,
757 IN UINTN NumberOfLines
,
758 IN CHAR16
*ArrayOfStrings
,
762 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, &ArrayOfStrings
);
767 IN UINTN MessageType
,
773 STATIC BOOLEAN InputError
;
774 CHAR16
*NvUpdateMessage
;
775 CHAR16
*InputErrorMessage
;
777 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
778 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
780 switch (MessageType
) {
783 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
785 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
786 gScreenDimensions
.BottomRow
- 1,
791 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
792 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
793 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, (CHAR16
*) L
" ");
800 case NV_UPDATE_REQUIRED
:
801 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
803 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
805 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
806 gScreenDimensions
.BottomRow
- 1,
809 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
811 gNvUpdateRequired
= TRUE
;
813 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
814 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
816 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
817 gScreenDimensions
.BottomRow
- 1,
822 gNvUpdateRequired
= FALSE
;
827 case REFRESH_STATUS_BAR
:
829 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
832 if (gNvUpdateRequired
) {
833 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
841 gBS
->FreePool (InputErrorMessage
);
842 gBS
->FreePool (NvUpdateMessage
);
848 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
849 IN CHAR16
*FormattedString
,
850 IN CHAR16
*OptionString
856 Used to remove the allocated data instances
864 EFI_FILE_FORM_TAGS
*FileForm
;
865 EFI_FILE_FORM_TAGS
*PreviousFileForm
;
866 EFI_FORM_TAGS
*FormTags
;
867 EFI_FORM_TAGS
*PreviousFormTags
;
868 EFI_IFR_BINARY
*IfrBinary
;
869 EFI_IFR_BINARY
*PreviousIfrBinary
;
870 EFI_INCONSISTENCY_DATA
*Inconsistent
;
871 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
872 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinition
;
876 FileForm
= FileFormTagsHead
;
878 if (FormattedString
!= NULL
) {
879 gBS
->FreePool (FormattedString
);
882 if (OptionString
!= NULL
) {
883 gBS
->FreePool (OptionString
);
886 for (; FileForm
!= NULL
;) {
887 PreviousFileForm
= NULL
;
890 // Advance FileForm to the last entry
892 for (; FileForm
->NextFile
!= NULL
; FileForm
= FileForm
->NextFile
) {
893 PreviousFileForm
= FileForm
;
896 FormTags
= &FileForm
->FormTags
;
898 for (; FormTags
!= NULL
;) {
899 FormTags
= &FileForm
->FormTags
;
900 PreviousFormTags
= NULL
;
903 // Advance FormTags to the last entry
905 for (; FormTags
->Next
!= NULL
; FormTags
= FormTags
->Next
) {
906 PreviousFormTags
= FormTags
;
909 // Walk through each of the tags and free the IntList allocation
911 for (Index
= 0; FormTags
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
; Index
++) {
913 // It is more than likely that the very last page will contain an end formset
915 if (FormTags
->Tags
[Index
].Operand
== EFI_IFR_END_FORM_SET_OP
) {
919 if (FormTags
->Tags
[Index
].IntList
!= NULL
) {
920 gBS
->FreePool (FormTags
->Tags
[Index
].IntList
);
924 if (PreviousFormTags
!= NULL
) {
925 gBS
->FreePool (FormTags
->Tags
);
926 FormTags
= PreviousFormTags
;
927 gBS
->FreePool (FormTags
->Next
);
928 FormTags
->Next
= NULL
;
930 gBS
->FreePool (FormTags
->Tags
);
935 // Last FileForm entry's Inconsistent database
937 Inconsistent
= FileForm
->InconsistentTags
;
940 // Advance Inconsistent to the last entry
942 for (; Inconsistent
->Next
!= NULL
; Inconsistent
= Inconsistent
->Next
)
945 for (; Inconsistent
!= NULL
;) {
947 // Preserve the Previous pointer
949 Buffer
= (VOID
*) Inconsistent
->Previous
;
952 // Free the current entry
954 gBS
->FreePool (Inconsistent
);
957 // Restore the Previous pointer
959 Inconsistent
= (EFI_INCONSISTENCY_DATA
*) Buffer
;
962 VariableDefinition
= FileForm
->VariableDefinitions
;
964 for (; VariableDefinition
!= NULL
;) {
965 VariableDefinition
= FileForm
->VariableDefinitions
;
966 PreviousVariableDefinition
= NULL
;
969 // Advance VariableDefinitions to the last entry
971 for (; VariableDefinition
->Next
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
972 PreviousVariableDefinition
= VariableDefinition
;
975 gBS
->FreePool (VariableDefinition
->VariableName
);
976 gBS
->FreePool (VariableDefinition
->NvRamMap
);
977 gBS
->FreePool (VariableDefinition
->FakeNvRamMap
);
979 if (PreviousVariableDefinition
!= NULL
) {
980 VariableDefinition
= PreviousVariableDefinition
;
981 gBS
->FreePool (VariableDefinition
->Next
);
982 VariableDefinition
->Next
= NULL
;
984 gBS
->FreePool (VariableDefinition
);
985 VariableDefinition
= NULL
;
989 if (PreviousFileForm
!= NULL
) {
990 FileForm
= PreviousFileForm
;
991 gBS
->FreePool (FileForm
->NextFile
);
992 FileForm
->NextFile
= NULL
;
994 gBS
->FreePool (FileForm
);
999 IfrBinary
= gBinaryDataHead
;
1001 for (; IfrBinary
!= NULL
;) {
1002 IfrBinary
= gBinaryDataHead
;
1003 PreviousIfrBinary
= NULL
;
1006 // Advance IfrBinary to the last entry
1008 for (; IfrBinary
->Next
!= NULL
; IfrBinary
= IfrBinary
->Next
) {
1009 PreviousIfrBinary
= IfrBinary
;
1012 gBS
->FreePool (IfrBinary
->IfrPackage
);
1014 if (PreviousIfrBinary
!= NULL
) {
1015 IfrBinary
= PreviousIfrBinary
;
1016 gBS
->FreePool (IfrBinary
->Next
);
1017 IfrBinary
->Next
= NULL
;
1019 gBS
->FreePool (IfrBinary
);
1024 gBS
->FreePool (gPreviousValue
);
1025 gPreviousValue
= NULL
;
1028 // Free Browser Strings
1030 gBS
->FreePool (gPressEnter
);
1031 gBS
->FreePool (gConfirmError
);
1032 gBS
->FreePool (gConfirmPassword
);
1033 gBS
->FreePool (gPromptForNewPassword
);
1034 gBS
->FreePool (gPromptForPassword
);
1035 gBS
->FreePool (gToggleCheckBox
);
1036 gBS
->FreePool (gNumericInput
);
1037 gBS
->FreePool (gMakeSelection
);
1038 gBS
->FreePool (gMoveHighlight
);
1039 gBS
->FreePool (gEscapeString
);
1040 gBS
->FreePool (gEnterCommitString
);
1041 gBS
->FreePool (gEnterString
);
1042 gBS
->FreePool (gFunctionOneString
);
1043 gBS
->FreePool (gFunctionTwoString
);
1044 gBS
->FreePool (gFunctionNineString
);
1045 gBS
->FreePool (gFunctionTenString
);
1051 SelectionsAreValid (
1052 IN UI_MENU_OPTION
*MenuOption
,
1053 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
1057 Routine Description:
1058 Initiate late consistency checks against the current page.
1069 EFI_FILE_FORM_TAGS
*FileFormTags
;
1071 CHAR16 NullCharacter
;
1076 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1078 StringPtr
= (CHAR16
*) L
"\0";
1079 NullCharacter
= CHAR_NULL
;
1081 FileFormTags
= FileFormTagsHead
;
1083 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
1084 FileFormTags
= FileFormTags
->NextFile
;
1087 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1088 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1090 Tag
= MenuOption
->ThisTag
;
1092 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
1093 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1096 // If the op-code has a late check, ensure consistency checks are now applied
1098 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
1099 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
1100 if (PopUp
!= 0x0000) {
1101 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
1103 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
1106 WaitForKeyStroke (&Key
);
1108 switch (Key
.UnicodeChar
) {
1110 case CHAR_CARRIAGE_RETURN
:
1112 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
1114 CopyMem (NvRamMap
, &Tag
->OldValue
, Tag
->StorageWidth
);
1115 gBS
->FreePool (StringPtr
);
1121 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1135 IN EFI_HII_HANDLE Handle
1139 Routine Description:
1140 Get the supported width for a particular op-code
1143 Tag - The Tag structure passed in.
1144 Handle - The handle in the HII database being used
1147 Returns the number of CHAR16 characters that is support.
1158 // See if the second text parameter is really NULL
1160 if ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Tag
->TextTwo
!= 0)) {
1161 String
= GetToken (Tag
->TextTwo
, Handle
);
1162 Size
= StrLen (String
);
1163 gBS
->FreePool (String
);
1166 if ((Tag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1167 (Tag
->Operand
== EFI_IFR_REF_OP
) ||
1168 (Tag
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1169 (Tag
->Operand
== EFI_IFR_STRING_OP
) ||
1170 (Tag
->Operand
== EFI_IFR_INVENTORY_OP
) ||
1172 // Allow a wide display if text op-code and no secondary text op-code
1174 ((Tag
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0x0000))
1176 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1178 return (UINT16
) gPromptBlockWidth
;
1184 IN CHAR16
*InputString
,
1185 IN UINT16 LineWidth
,
1186 IN OUT UINTN
*Index
,
1187 OUT CHAR16
**OutputString
1191 Routine Description:
1192 Will copy LineWidth amount of a string in the OutputString buffer and return the
1193 number of CHAR16 characters that were copied into the OutputString buffer.
1196 InputString - String description for this option.
1197 LineWidth - Width of the desired string to extract in CHAR16 characters
1198 Index - Where in InputString to start the copy process
1199 OutputString - Buffer to copy the string into
1202 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1207 static BOOLEAN Finished
;
1219 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1222 // Ensure we have got a valid buffer
1224 if (*OutputString
!= NULL
) {
1227 //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.
1228 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1230 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1231 *Index
= *Index
+ 2;
1235 // Fast-forward the string and see if there is a carriage-return in the string
1237 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1241 // Copy the desired LineWidth of data to the output buffer.
1242 // Also make sure that we don't copy more than the string.
1243 // Also make sure that if there are linefeeds, we account for them.
1245 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1246 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1249 // Convert to CHAR16 value and show that we are done with this operation
1251 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1252 if (LineWidth
!= 0) {
1256 if (Count2
== LineWidth
) {
1258 // Rewind the string from the maximum size until we see a space to break the line
1260 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1262 if (LineWidth
== 0) {
1270 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1273 // If currently pointing to a space, increment the index to the first non-space character
1276 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1280 *Index
= (UINT16
) (*Index
+ LineWidth
);
1289 UpdateOptionSkipLines (
1290 IN EFI_IFR_DATA_ARRAY
*PageData
,
1291 IN UI_MENU_OPTION
*MenuOption
,
1292 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1293 IN CHAR16
**OptionalString
,
1301 CHAR16
*OutputString
;
1302 CHAR16
*OptionString
;
1305 OptionString
= *OptionalString
;
1306 OutputString
= NULL
;
1308 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1310 if (OptionString
!= NULL
) {
1311 Width
= (UINT16
) gOptionBlockWidth
;
1315 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1317 // If there is more string to process print on the next row and increment the Skip value
1319 if (StrLen (&OptionString
[Index
])) {
1320 if (SkipValue
== 0) {
1323 // Since the Number of lines for this menu entry may or may not be reflected accurately
1324 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1325 // some testing to ensure we are keeping this in-sync.
1327 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1329 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1335 gBS
->FreePool (OutputString
);
1336 if (SkipValue
!= 0) {
1344 *OptionalString
= OptionString
;
1347 // Search table for UiDisplayMenu()
1349 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
1351 { SCAN_DOWN
, UiDown
},
1352 { SCAN_PAGE_UP
, UiPageUp
},
1353 { SCAN_PAGE_DOWN
, UiPageDown
},
1354 { SCAN_ESC
, UiReset
},
1355 { SCAN_F2
, UiPrevious
},
1356 { SCAN_LEFT
, UiLeft
},
1357 { SCAN_RIGHT
, UiRight
},
1358 { SCAN_F9
, UiDefault
},
1359 { SCAN_F10
, UiSave
}
1362 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
1363 { UiNoOperation
, CfUiNoOperation
},
1364 { UiDefault
, CfUiDefault
},
1365 { UiSelect
, CfUiSelect
},
1367 { UiDown
, CfUiDown
},
1368 { UiLeft
, CfUiLeft
},
1369 { UiRight
, CfUiRight
},
1370 { UiReset
, CfUiReset
},
1371 { UiSave
, CfUiSave
},
1372 { UiPrevious
, CfUiPrevious
},
1373 { UiPageUp
, CfUiPageUp
},
1374 { UiPageDown
, CfUiPageDown
}
1380 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1381 OUT EFI_IFR_DATA_ARRAY
*PageData
1385 Routine Description:
1386 Display menu and wait for user to select one menu option, then return it.
1387 If AutoBoot is enabled, then if user doesn't select any option,
1388 after period of time, it will automatically return the first menu option.
1391 SubMenu - Indicate is sub menu.
1392 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.
1393 PageData - A pointer to the EFI_IFR_DATA_ARRAY.
1396 Return the pointer of the menu which selected,
1397 otherwise return NULL.
1412 UINTN DataAndTimeLineNumberPad
;
1414 INT16 OriginalTimeOut
;
1418 CHAR16
*OptionString
;
1419 CHAR16
*OutputString
;
1420 CHAR16
*FormattedString
;
1427 UI_MENU_LIST
*UiMenuList
;
1431 LIST_ENTRY
*TopOfScreen
;
1432 LIST_ENTRY
*SavedListEntry
;
1433 UI_MENU_OPTION
*Selection
;
1434 UI_MENU_OPTION
*MenuOption
;
1435 UI_MENU_OPTION
*NextMenuOption
;
1436 UI_MENU_OPTION
*SavedMenuOption
;
1437 UI_MENU_OPTION
*PreviousMenuOption
;
1438 EFI_IFR_BINARY
*IfrBinary
;
1439 UI_CONTROL_FLAG ControlFlag
;
1440 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1441 EFI_FILE_FORM_TAGS
*FileFormTags
;
1442 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1443 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
1444 UI_SCREEN_OPERATION ScreenOperation
;
1445 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1446 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1447 EFI_HII_VARIABLE_PACK_LIST
*NvMapListHead
;
1448 EFI_HII_VARIABLE_PACK_LIST
*NvMapListNode
;
1452 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1454 VariableDefinition
= NULL
;
1455 Status
= EFI_SUCCESS
;
1456 FormattedString
= NULL
;
1457 OptionString
= NULL
;
1458 ScreenOperation
= UiNoOperation
;
1460 FormCallback
= NULL
;
1461 FileFormTags
= NULL
;
1462 OutputString
= NULL
;
1467 MenuRefreshEntry
= gMenuRefreshHead
;
1468 OldMenuRefreshEntry
= gMenuRefreshHead
;
1469 NextMenuOption
= NULL
;
1470 PreviousMenuOption
= NULL
;
1471 SavedMenuOption
= NULL
;
1476 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1478 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
1479 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1480 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1482 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1483 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1487 Col
= LocalScreen
.LeftColumn
;
1489 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1492 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1494 TopOfScreen
= Menu
.ForwardLink
;
1499 // Get user's selection
1502 NewPos
= Menu
.ForwardLink
;
1503 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1505 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1507 ControlFlag
= CfInitialization
;
1510 switch (ControlFlag
) {
1511 case CfInitialization
:
1512 ControlFlag
= CfCheckSelection
;
1513 if (gExitRequired
) {
1514 ScreenOperation
= UiReset
;
1515 ControlFlag
= CfScreenOperation
;
1516 } else if (gSaveRequired
) {
1517 ScreenOperation
= UiSave
;
1518 ControlFlag
= CfScreenOperation
;
1519 } else if (IsListEmpty (&Menu
)) {
1520 ControlFlag
= CfReadKey
;
1524 case CfCheckSelection
:
1525 if (Selection
!= NULL
) {
1526 ControlFlag
= CfExit
;
1528 ControlFlag
= CfRepaint
;
1531 FileFormTags
= FileFormTagsHead
;
1535 ControlFlag
= CfRefreshHighLight
;
1541 SavedMenuOption
= MenuOption
;
1550 LocalScreen
.LeftColumn
,
1551 LocalScreen
.RightColumn
,
1552 TopRow
- SCROLL_ARROW_HEIGHT
,
1553 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1554 FIELD_TEXT
| FIELD_BACKGROUND
1557 while (gMenuRefreshHead
!= NULL
) {
1558 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
1560 gBS
->FreePool (gMenuRefreshHead
);
1562 gMenuRefreshHead
= OldMenuRefreshEntry
;
1565 for (Link
= TopOfScreen
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1566 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1567 MenuOption
->Row
= Row
;
1569 MenuOption
->Col
= Col
;
1570 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1573 if (MenuOption
->ThisTag
->GrayOut
) {
1574 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1576 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1577 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1581 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1585 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1586 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1587 PrintStringAt (Col
, Row
, OutputString
);
1590 // If there is more string to process print on the next row and increment the Skip value
1592 if (StrLen (&MenuOption
->Description
[Index
])) {
1598 gBS
->FreePool (OutputString
);
1608 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1609 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1611 if (OptionString
!= NULL
) {
1612 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1613 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1616 // If leading spaces on OptionString - remove the spaces
1618 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1619 MenuOption
->OptCol
++;
1622 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1623 OptionString
[Count
] = OptionString
[Index
];
1627 OptionString
[Count
] = CHAR_NULL
;
1631 // If this is a date or time op-code and is used to reflect an RTC, register the op-code
1633 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1634 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
) &&
1635 (MenuOption
->ThisTag
->StorageStart
>= FileFormTags
->FormTags
.Tags
[0].NvDataSize
)) {
1637 if (gMenuRefreshHead
== NULL
) {
1638 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1639 ASSERT (MenuRefreshEntry
!= NULL
);
1640 MenuRefreshEntry
->MenuOption
= MenuOption
;
1641 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1642 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1643 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1644 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1645 gMenuRefreshHead
= MenuRefreshEntry
;
1648 // Advance to the last entry
1650 for (MenuRefreshEntry
= gMenuRefreshHead
;
1651 MenuRefreshEntry
->Next
!= NULL
;
1652 MenuRefreshEntry
= MenuRefreshEntry
->Next
1655 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1656 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1657 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1658 MenuRefreshEntry
->MenuOption
= MenuOption
;
1659 MenuRefreshEntry
->FileFormTagsHead
= FileFormTagsHead
;
1660 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1661 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1662 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1666 Width
= (UINT16
) gOptionBlockWidth
;
1670 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1671 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1672 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1675 // If there is more string to process print on the next row and increment the Skip value
1677 if (StrLen (&OptionString
[Index
])) {
1681 // Since the Number of lines for this menu entry may or may not be reflected accurately
1682 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1683 // some testing to ensure we are keeping this in-sync.
1685 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1687 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1693 gBS
->FreePool (OutputString
);
1703 // If this is a text op with secondary text information
1705 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
) && (MenuOption
->ThisTag
->TextTwo
!= 0)) {
1706 StringPtr
= GetToken (MenuOption
->ThisTag
->TextTwo
, MenuOption
->Handle
);
1708 Width
= (UINT16
) gOptionBlockWidth
;
1712 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1713 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1714 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1717 // If there is more string to process print on the next row and increment the Skip value
1719 if (StrLen (&StringPtr
[Index
])) {
1723 // Since the Number of lines for this menu entry may or may not be reflected accurately
1724 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1725 // some testing to ensure we are keeping this in-sync.
1727 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1729 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1735 gBS
->FreePool (OutputString
);
1742 gBS
->FreePool (StringPtr
);
1746 // For now, assume left-justified 72 width max setup entries
1748 PrintStringAt (Col
, Row
, MenuOption
->Description
);
1751 // Tracker 6210 - need to handle the bottom of the display
1753 if (MenuOption
->Skip
> 1) {
1754 Row
+= MenuOption
->Skip
- SkipValue
;
1757 Row
+= MenuOption
->Skip
;
1760 if (Row
> BottomRow
) {
1761 if (!ValueIsScroll (FALSE
, Link
)) {
1765 Row
= BottomRow
+ 1;
1770 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1775 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1777 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1778 TopRow
- SCROLL_ARROW_HEIGHT
,
1782 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1786 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1788 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1789 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1793 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1796 if (SavedMenuOption
!= NULL
) {
1797 MenuOption
= SavedMenuOption
;
1802 case CfRefreshHighLight
:
1803 ControlFlag
= CfUpdateHelpString
;
1805 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1806 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1808 SavedValue
= Repaint
;
1811 if (NewPos
!= NULL
) {
1812 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1814 if (gLastOpr
&& (gEntryNumber
!= -1)) {
1815 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1816 if (gEntryNumber
!= MenuOption
->EntryNumber
) {
1817 ScreenOperation
= UiDown
;
1818 ControlFlag
= CfScreenOperation
;
1825 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1826 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1827 if (OptionString
!= NULL
) {
1828 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1829 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1832 // If leading spaces on OptionString - remove the spaces
1834 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1837 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1838 OptionString
[Count
] = OptionString
[Index
];
1842 OptionString
[Count
] = CHAR_NULL
;
1845 Width
= (UINT16
) gOptionBlockWidth
;
1847 OriginalRow
= MenuOption
->Row
;
1849 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1850 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1851 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1854 // If there is more string to process print on the next row and increment the Skip value
1856 if (StrLen (&OptionString
[Index
])) {
1860 gBS
->FreePool (OutputString
);
1863 MenuOption
->Row
= OriginalRow
;
1866 if (MenuOption
->ThisTag
->GrayOut
) {
1867 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1869 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1870 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1874 OriginalRow
= MenuOption
->Row
;
1875 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1877 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1878 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1879 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1882 // If there is more string to process print on the next row and increment the Skip value
1884 if (StrLen (&MenuOption
->Description
[Index
])) {
1888 gBS
->FreePool (OutputString
);
1891 MenuOption
->Row
= OriginalRow
;
1892 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1896 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1897 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
1900 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
1902 if ((gPriorMenuEntry
!= 0) && (MenuOption
->EntryNumber
!= gPriorMenuEntry
) && (NewPos
->ForwardLink
!= &Menu
)) {
1903 ScreenOperation
= UiDown
;
1904 ControlFlag
= CfScreenOperation
;
1907 gPriorMenuEntry
= 0;
1910 // This is only possible if we entered this page and the first menu option is
1911 // a "non-menu" item. In that case, force it UiDown
1913 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
1915 // If we previously hit an UP command and we are still sitting on a text operation
1916 // we must continue going up
1918 if (ScreenOperation
== UiUp
) {
1919 ControlFlag
= CfScreenOperation
;
1922 ScreenOperation
= UiDown
;
1923 ControlFlag
= CfScreenOperation
;
1928 // Set reverse attribute
1930 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
1931 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1934 // Assuming that we have a refresh linked-list created, lets annotate the
1935 // appropriate entry that we are highlighting with its new attribute. Just prior to this
1936 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
1938 if (gMenuRefreshHead
!= NULL
) {
1939 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
1940 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1941 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
1942 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
;
1948 ProcessOptions (MenuOption
, FALSE
, FileFormTagsHead
, PageData
, &OptionString
);
1949 if (OptionString
!= NULL
) {
1950 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
1951 MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
1954 // If leading spaces on OptionString - remove the spaces
1956 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
1959 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1960 OptionString
[Count
] = OptionString
[Index
];
1964 OptionString
[Count
] = CHAR_NULL
;
1966 Width
= (UINT16
) gOptionBlockWidth
;
1968 OriginalRow
= MenuOption
->Row
;
1970 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1971 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1972 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1975 // If there is more string to process print on the next row and increment the Skip value
1977 if (StrLen (&OptionString
[Index
])) {
1981 gBS
->FreePool (OutputString
);
1984 MenuOption
->Row
= OriginalRow
;
1987 OriginalRow
= MenuOption
->Row
;
1989 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
1991 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1992 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
1993 PrintStringAt (Col
, MenuOption
->Row
, OutputString
);
1996 // If there is more string to process print on the next row and increment the Skip value
1998 if (StrLen (&MenuOption
->Description
[Index
])) {
2002 gBS
->FreePool (OutputString
);
2005 MenuOption
->Row
= OriginalRow
;
2010 if (((NewPos
->ForwardLink
!= &Menu
) && (ScreenOperation
== UiDown
)) ||
2011 ((NewPos
->BackLink
!= &Menu
) && (ScreenOperation
== UiUp
)) ||
2012 (ScreenOperation
== UiNoOperation
)
2014 UpdateKeyHelp (MenuOption
, FALSE
);
2017 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2020 // Clear reverse attribute
2022 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2025 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2026 // if we didn't break halfway when process CfRefreshHighLight.
2028 Repaint
= SavedValue
;
2031 case CfUpdateHelpString
:
2032 ControlFlag
= CfPrepareToReadKey
;
2035 (Repaint
|| NewLine
||
2036 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2037 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) &&
2038 !(gClassOfVfr
== EFI_GENERAL_APPLICATION_SUBCLASS
)) {
2040 // Don't print anything if it is a NULL help token
2042 if (MenuOption
->ThisTag
->Help
== 0x00000000) {
2043 StringPtr
= (CHAR16
*) L
"\0";
2045 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2048 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2050 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2052 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2054 // Pad String with spaces to simulate a clearing of the previous line
2056 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
]) / 2 < gHelpBlockWidth
;) {
2057 StrCat (&FormattedString
[Index
* gHelpBlockWidth
], (CHAR16
*) L
" ");
2061 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2063 &FormattedString
[Index
* gHelpBlockWidth
]
2068 // Reset this flag every time we finish using it.
2074 case CfPrepareToReadKey
:
2075 ControlFlag
= CfReadKey
;
2077 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
2078 FileFormTags
= FileFormTags
->NextFile
;
2081 ScreenOperation
= UiNoOperation
;
2083 Status
= gBS
->HandleProtocol (
2084 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
2085 &gEfiFormCallbackProtocolGuid
,
2086 (VOID
**) &FormCallback
2092 ControlFlag
= CfScreenOperation
;
2094 OriginalTimeOut
= FrontPageTimeOutValue
;
2096 if (FrontPageTimeOutValue
>= 0 && (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) && FrontPageTimeOutValue
!= (INT16
) -1) {
2098 // Remember that if set to 0, must immediately boot an option
2100 if (FrontPageTimeOutValue
== 0) {
2101 FrontPageTimeOutValue
= 0xFFFF;
2102 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2103 if (EFI_ERROR (Status
)) {
2104 Status
= EFI_TIMEOUT
;
2109 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, ONE_SECOND
);
2110 if (Status
== EFI_TIMEOUT
) {
2111 EFI_IFR_DATA_ENTRY
*DataEntry
;
2113 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
2115 PageData
->EntryCount
= 1;
2116 Count
= (UINT32
) ((OriginalTimeOut
- FrontPageTimeOutValue
) * 100 / OriginalTimeOut
);
2117 CopyMem (&DataEntry
->Data
, &Count
, sizeof (UINT32
));
2119 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2120 FormCallback
->Callback (
2123 (EFI_IFR_DATA_ARRAY
*) PageData
,
2128 // Count down 1 second
2130 FrontPageTimeOutValue
--;
2133 ASSERT (!EFI_ERROR (Status
));
2134 PageData
->EntryCount
= 0;
2135 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
2136 FormCallback
->Callback (
2139 (EFI_IFR_DATA_ARRAY
*) PageData
,
2144 FrontPageTimeOutValue
= 0xFFFF;
2148 // Wait for user's selection, no auto boot
2150 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
2152 } while (Status
== EFI_TIMEOUT
);
2156 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2157 DisableQuietBoot ();
2160 if (Status
== EFI_TIMEOUT
) {
2161 Key
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
2163 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2165 // if we encounter error, continue to read another key in.
2167 if (EFI_ERROR (Status
)) {
2168 ControlFlag
= CfReadKey
;
2173 switch (Key
.UnicodeChar
) {
2174 case CHAR_CARRIAGE_RETURN
:
2175 Selection
= MenuOption
;
2176 ScreenOperation
= UiSelect
;
2181 // We will push the adjustment of these numeric values directly to the input handler
2185 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2187 if (Key
.UnicodeChar
== '+') {
2188 gDirection
= SCAN_RIGHT
;
2190 gDirection
= SCAN_LEFT
;
2193 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, NULL
, &OptionString
);
2198 ScreenOperation
= UiUp
;
2203 ScreenOperation
= UiDown
;
2207 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
2209 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !(MenuOption
->ThisTag
->GrayOut
)) {
2210 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2211 gST
->ConOut
->OutputString (gST
->ConOut
, MenuOption
->Description
);
2212 Selection
= MenuOption
;
2213 ScreenOperation
= UiSelect
;
2220 if (((Key
.ScanCode
== SCAN_F1
) && ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
)) ||
2221 ((Key
.ScanCode
== SCAN_F2
) && ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
)) ||
2222 ((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2223 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2226 // If the function key has been disabled, just ignore the key.
2229 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2230 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2231 if ((Key
.ScanCode
== SCAN_F9
) || (Key
.ScanCode
== SCAN_F10
)) {
2233 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2236 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2245 case CfScreenOperation
:
2246 IfrBinary
= gBinaryDataHead
;
2249 // Advance to the Ifr we are using
2251 for (Index
= 0; Index
< gActiveIfr
; Index
++) {
2252 IfrBinary
= IfrBinary
->Next
;
2255 if (ScreenOperation
!= UiPrevious
&& ScreenOperation
!= UiReset
) {
2257 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2258 // ignore the selection and go back to reading keys.
2260 if (IsListEmpty (&Menu
)) {
2261 ControlFlag
= CfReadKey
;
2265 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2267 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
2268 NextMenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2269 if (!(NextMenuOption
->ThisTag
->GrayOut
) && (NextMenuOption
->ThisTag
->Operand
!= EFI_IFR_SUBTITLE_OP
)) {
2274 if (Link
== &Menu
) {
2275 ControlFlag
= CfPrepareToReadKey
;
2281 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2284 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2285 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2292 ControlFlag
= CfCheckSelection
;
2294 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2296 if (MenuOption
!= NULL
) {
2297 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2304 if (IsListEmpty (&gMenuList
)) {
2306 if (IsListEmpty (&Menu
)) {
2307 ControlFlag
= CfReadKey
;
2314 while (gMenuRefreshHead
!= NULL
) {
2315 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
2317 gBS
->FreePool (gMenuRefreshHead
);
2319 gMenuRefreshHead
= OldMenuRefreshEntry
;
2322 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag
2325 UiRemoveMenuListEntry (MenuOption
, &Selection
);
2326 Selection
->Previous
= TRUE
;
2331 gActiveIfr
= Selection
->IfrNumber
;
2335 ControlFlag
= CfCheckSelection
;
2337 ExtractRequestedNvMap (FileFormTags
, MenuOption
->ThisTag
->VariableNumber
, &VariableDefinition
);
2340 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_TEXT_OP
&&
2341 !(MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
)) ||
2342 (MenuOption
->ThisTag
->GrayOut
) ||
2343 (MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2344 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2350 UpdateKeyHelp (MenuOption
, TRUE
);
2351 Status
= ProcessOptions (MenuOption
, TRUE
, FileFormTagsHead
, PageData
, &OptionString
);
2353 if (EFI_ERROR (Status
)) {
2359 if (OptionString
!= NULL
) {
2360 PrintStringAt (LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ 1, MenuOption
->Row
, OptionString
);
2363 if (MenuOption
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
2364 Selection
= MenuOption
;
2367 if (Selection
== NULL
) {
2371 Location
= (UINT8
*) &PageData
->EntryCount
;
2374 // If not a goto, dump single piece of data, otherwise dump everything
2376 if (Selection
->ThisTag
->Operand
== EFI_IFR_REF_OP
) {
2378 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2380 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2386 UiAddMenuListEntry (Selection
);
2387 gPriorMenuEntry
= 0;
2390 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious
2392 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
2393 UiMenuList
->FormerEntryNumber
= MenuOption
->EntryNumber
;
2398 // Rewind to the beginning of the menu
2400 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2404 // Get Total Count of Menu entries
2406 for (Count
= 1; NewPos
->ForwardLink
!= &Menu
; NewPos
= NewPos
->ForwardLink
) {
2410 // Rewind to the beginning of the menu
2412 for (; NewPos
->BackLink
!= &Menu
; NewPos
= NewPos
->BackLink
)
2416 // Copy the number of entries being described to the PageData location
2418 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2420 for (Index
= 4; NewPos
->ForwardLink
!= &Menu
; Index
= Index
+ MenuOption
->ThisTag
->StorageWidth
+ 2) {
2422 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2423 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2424 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2426 &Location
[Index
+ 4],
2427 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2428 MenuOption
->ThisTag
->StorageWidth
2430 NewPos
= NewPos
->ForwardLink
;
2434 gPriorMenuEntry
= MenuOption
->EntryNumber
;
2439 // Copy the number of entries being described to the PageData location
2441 CopyMem (&Location
[0], &Count
, sizeof (UINT32
));
2444 // Start at PageData[4] since the EntryCount is a UINT32
2449 // Copy data to destination
2451 Location
[Index
] = MenuOption
->ThisTag
->Operand
;
2452 Location
[Index
+ 1] = (UINT8
) (MenuOption
->ThisTag
->StorageWidth
+ 4);
2454 &Location
[Index
+ 4],
2455 &VariableDefinition
->NvRamMap
[MenuOption
->ThisTag
->StorageStart
],
2456 MenuOption
->ThisTag
->StorageWidth
2463 ControlFlag
= CfCheckSelection
;
2465 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
2469 // If NV flag is up, prompt user
2471 if (gNvUpdateRequired
) {
2472 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2474 YesResponse
= gYesResponse
[0];
2475 NoResponse
= gNoResponse
[0];
2478 CreateDialog (3, TRUE
, 0, NULL
, &Key
, gEmptyString
, gAreYouSure
, gEmptyString
);
2481 (Key
.ScanCode
!= SCAN_ESC
) &&
2482 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2483 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2487 // If the user hits the YesResponse key
2489 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2497 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2499 if (MenuOption
!= NULL
) {
2500 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2508 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2509 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
2513 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2517 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2518 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2520 if (IfrBinary
->UnRegisterOnExit
) {
2521 Hii
->RemovePack (Hii
, MenuOption
->Handle
);
2527 // Clean up the allocated data buffers
2529 FreeData (FileFormTagsHead
, FormattedString
, OptionString
);
2531 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2535 ControlFlag
= CfCheckSelection
;
2536 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2537 if (MenuOption
->Skip
== 1) {
2539 // In the tail of the Date/Time op-code set, go left.
2541 NewPos
= NewPos
->BackLink
;
2544 // In the middle of the Data/Time op-code set, go left.
2546 NextMenuOption
= CR (NewPos
->ForwardLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2547 if (NextMenuOption
->Skip
== 1) {
2548 NewPos
= NewPos
->BackLink
;
2555 ControlFlag
= CfCheckSelection
;
2556 if ((MenuOption
->Skip
== 0) &&
2557 ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
))
2560 // We are in the head or middle of the Date/Time op-code set, advance right.
2562 NewPos
= NewPos
->ForwardLink
;
2567 ControlFlag
= CfCheckSelection
;
2569 if (NewPos
->BackLink
!= &Menu
) {
2572 // Adjust Date/Time position before we advance forward.
2574 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2577 // Caution that we have already rewind to the top, don't go backward in this situation.
2579 if (NewPos
->BackLink
!= &Menu
) {
2580 NewPos
= NewPos
->BackLink
;
2583 PreviousMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2586 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2587 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2588 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2589 // checking can be done.
2591 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2595 // If the previous MenuOption contains a display-only op-code, skip to the next one
2597 if (PreviousMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| PreviousMenuOption
->ThisTag
->GrayOut
) {
2599 // This is ok as long as not at the end of the list
2601 if (NewPos
->BackLink
== &Menu
) {
2603 // If we are at the start of the list, then this list must start with a display only
2604 // piece of data, so do not allow the backward motion
2606 ScreenOperation
= UiDown
;
2608 if (PreviousMenuOption
->Row
<= TopRow
) {
2609 if (TopOfScreen
->BackLink
!= &Menu
) {
2610 TopOfScreen
= TopOfScreen
->BackLink
;
2615 UpdateStatusBar (INPUT_ERROR
, PreviousMenuOption
->ThisTag
->Flags
, FALSE
);
2621 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2622 // don't worry about a redraw.
2624 if ((MenuOption
->Row
- PreviousMenuOption
->Skip
- DataAndTimeLineNumberPad
< TopRow
) ||
2625 (PreviousMenuOption
->Skip
> MenuOption
->Row
)
2628 if (TopOfScreen
->BackLink
== &Menu
) {
2635 // Is the current top of screen a zero-advance op-code?
2636 // If so, keep moving forward till we hit a >0 advance op-code
2638 SavedMenuOption
= CR (TopOfScreen
->BackLink
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2639 TopOfScreen
= TopOfScreen
->BackLink
;
2640 } while (SavedMenuOption
->Skip
== 0);
2642 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2644 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2647 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2650 SavedMenuOption
= MenuOption
;
2651 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2652 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2654 // If we are at the end of the list and sitting on a text op, we need to more forward
2656 ScreenOperation
= UiDown
;
2657 ControlFlag
= CfScreenOperation
;
2661 MenuOption
= SavedMenuOption
;
2667 ControlFlag
= CfCheckSelection
;
2669 SavedListEntry
= NewPos
;
2671 for (Index
= BottomRow
; Index
>= TopRow
+ 1; Index
-= MenuOption
->Skip
) {
2672 if (Link
->BackLink
== &Menu
) {
2674 Link
= SavedListEntry
;
2675 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2681 Link
= Link
->BackLink
;
2682 MenuOption
= CR (Link
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2684 SavedListEntry
= Link
;
2690 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2691 // Don't do this when we are already in the first page.
2694 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2695 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2696 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2701 ControlFlag
= CfCheckSelection
;
2703 SavedListEntry
= NewPos
;
2705 NewPos
= TopOfScreen
;
2706 for (Index
= TopRow
; Index
<= BottomRow
- 1; Index
+= MenuOption
->Skip
) {
2707 if (NewPos
->ForwardLink
== &Menu
) {
2708 NewPos
= SavedListEntry
;
2709 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2718 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2719 NewPos
= NewPos
->ForwardLink
;
2726 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2727 // Don't do this when we are already in the last page.
2730 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2731 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2732 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2737 ControlFlag
= CfCheckSelection
;
2739 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2740 // to be one that progresses to the next set of op-codes, we need to advance to the last
2741 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2742 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2743 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2744 // the Date/Time op-code.
2746 DataAndTimeLineNumberPad
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2748 if (NewPos
->ForwardLink
!= &Menu
) {
2750 NewPos
= NewPos
->ForwardLink
;
2751 NextMenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2755 // If the next MenuOption contains a display-only op-code, skip to the next one
2756 // Also if the next MenuOption is date or time,
2758 if (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| NextMenuOption
->ThisTag
->GrayOut
) {
2760 // This is ok as long as not at the end of the list
2762 if (NewPos
== &Menu
) {
2764 // If we are at the end of the list, then this list must end with a display only
2765 // piece of data, so do not allow the forward motion
2767 UpdateStatusBar (INPUT_ERROR
, NextMenuOption
->ThisTag
->Flags
, FALSE
);
2768 NewPos
= NewPos
->BackLink
;
2769 ScreenOperation
= UiUp
;
2775 // An option might be multi-line, so we need to reflect that data in the overall skip value
2777 UpdateOptionSkipLines (PageData
, NextMenuOption
, FileFormTagsHead
, &OptionString
, SkipValue
);
2779 if (NextMenuOption
->Skip
> 1) {
2780 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ NextMenuOption
->Skip
- 1;
2782 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DataAndTimeLineNumberPad
;
2785 // If we are going to scroll
2787 if (Temp
> BottomRow
) {
2790 // Is the current top of screen a zero-advance op-code?
2791 // If so, keep moving forward till we hit a >0 advance op-code
2793 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2796 // If bottom op-code is more than one line or top op-code is more than one line
2798 if ((NextMenuOption
->Skip
> 1) || (MenuOption
->Skip
> 1)) {
2800 // Is the bottom op-code greater than or equal in size to the top op-code?
2802 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
2804 // Skip the top op-code
2806 TopOfScreen
= TopOfScreen
->ForwardLink
;
2807 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
2809 OldSkipValue
= Difference
;
2811 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2814 // If we have a remainder, skip that many more op-codes until we drain the remainder
2817 Difference
>= (INTN
) SavedMenuOption
->Skip
;
2818 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
2821 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2823 TopOfScreen
= TopOfScreen
->ForwardLink
;
2824 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2825 if (Difference
< (INTN
) SavedMenuOption
->Skip
) {
2826 Difference
= SavedMenuOption
->Skip
- Difference
- 1;
2829 if (Difference
== (INTN
) SavedMenuOption
->Skip
) {
2830 TopOfScreen
= TopOfScreen
->ForwardLink
;
2831 SavedMenuOption
= CR (TopOfScreen
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2832 Difference
= SavedMenuOption
->Skip
- Difference
;
2838 // Since we will act on this op-code in the next routine, and increment the
2839 // SkipValue, set the skips to one less than what is required.
2841 SkipValue
= Difference
- 1;
2845 // Since we will act on this op-code in the next routine, and increment the
2846 // SkipValue, set the skips to one less than what is required.
2848 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
2851 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2852 TopOfScreen
= TopOfScreen
->ForwardLink
;
2855 SkipValue
= OldSkipValue
;
2859 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2860 // Let's set a skip flag to smoothly scroll the top of the screen.
2862 if (SavedMenuOption
->Skip
> 1) {
2863 if (SavedMenuOption
== NextMenuOption
) {
2870 TopOfScreen
= TopOfScreen
->ForwardLink
;
2872 } while (SavedMenuOption
->Skip
== 0);
2875 OldSkipValue
= SkipValue
;
2878 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2882 SavedMenuOption
= MenuOption
;
2883 MenuOption
= CR (NewPos
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
2884 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
) {
2886 // If we are at the end of the list and sitting on a text op, we need to more forward
2888 ScreenOperation
= UiUp
;
2889 ControlFlag
= CfScreenOperation
;
2893 MenuOption
= SavedMenuOption
;
2895 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2897 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2903 ControlFlag
= CfCheckSelection
;
2905 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.
2907 if (MenuOption
!= NULL
) {
2908 if (!SelectionsAreValid (MenuOption
, FileFormTagsHead
)) {
2915 // If callbacks are active, and the callback has a Write method, try to use it
2917 if (FileFormTags
->VariableDefinitions
->VariableName
== NULL
) {
2918 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2919 Status
= FormCallback
->NvWrite (
2921 (CHAR16
*) L
"Setup",
2922 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2923 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2924 VariableDefinition
->VariableSize
,
2925 (VOID
*) VariableDefinition
->NvRamMap
,
2930 Status
= gRT
->SetVariable (
2931 (CHAR16
*) L
"Setup",
2932 &FileFormTags
->FormTags
.Tags
[0].GuidValue
,
2933 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2934 VariableDefinition
->VariableSize
,
2935 (VOID
*) VariableDefinition
->NvRamMap
2939 VariableDefinition
= FileFormTags
->VariableDefinitions
;
2941 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
2942 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
2943 Status
= FormCallback
->NvWrite (
2945 VariableDefinition
->VariableName
,
2946 &VariableDefinition
->Guid
,
2947 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2948 VariableDefinition
->VariableSize
,
2949 (VOID
*) VariableDefinition
->NvRamMap
,
2954 Status
= gRT
->SetVariable (
2955 VariableDefinition
->VariableName
,
2956 &VariableDefinition
->Guid
,
2957 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2958 VariableDefinition
->VariableSize
,
2959 (VOID
*) VariableDefinition
->NvRamMap
2965 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->Flags
, FALSE
);
2966 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, FALSE
);
2970 ControlFlag
= CfCheckSelection
;
2972 NvMapListHead
= NULL
;
2974 Status
= Hii
->GetDefaultImage (Hii
, MenuOption
->Handle
, EFI_IFR_FLAG_DEFAULT
, &NvMapListHead
);
2976 if (!EFI_ERROR (Status
)) {
2977 ASSERT_EFI_ERROR (NULL
!= NvMapListHead
);
2979 NvMapListNode
= NvMapListHead
;
2981 while (NULL
!= NvMapListNode
) {
2982 if (FileFormTags
->VariableDefinitions
->VariableId
== NvMapListNode
->VariablePack
->VariableId
) {
2983 NvMap
= (VOID
*) ((CHAR8
*) NvMapListNode
->VariablePack
+ sizeof (EFI_HII_VARIABLE_PACK
) + NvMapListNode
->VariablePack
->VariableNameLength
);
2984 NvMapSize
= NvMapListNode
->VariablePack
->Header
.Length
- sizeof (EFI_HII_VARIABLE_PACK
) - NvMapListNode
->VariablePack
->VariableNameLength
;
2987 NvMapListNode
= NvMapListNode
->NextVariablePack
;
2991 // Free the buffer that was allocated.
2993 gBS
->FreePool (FileFormTags
->VariableDefinitions
->NvRamMap
);
2994 gBS
->FreePool (FileFormTags
->VariableDefinitions
->FakeNvRamMap
);
2997 // Allocate, copy the NvRamMap.
2999 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
- FileFormTags
->VariableDefinitions
->VariableSize
);
3000 FileFormTags
->VariableDefinitions
->VariableSize
= (UINT16
) NvMapSize
;
3001 FileFormTags
->VariableDefinitions
->VariableFakeSize
= (UINT16
) (FileFormTags
->VariableDefinitions
->VariableFakeSize
+ FileFormTags
->VariableDefinitions
->VariableSize
);
3003 FileFormTags
->VariableDefinitions
->NvRamMap
= AllocateZeroPool (FileFormTags
->VariableDefinitions
->VariableSize
);
3004 ASSERT (FileFormTags
->VariableDefinitions
->NvRamMap
!= NULL
);
3006 FileFormTags
->VariableDefinitions
->FakeNvRamMap
= AllocateZeroPool (NvMapSize
+ FileFormTags
->VariableDefinitions
->VariableFakeSize
);
3007 ASSERT (FileFormTags
->VariableDefinitions
->FakeNvRamMap
!= NULL
);
3009 CopyMem (FileFormTags
->VariableDefinitions
->NvRamMap
, NvMap
, NvMapSize
);
3010 gBS
->FreePool (NvMapListHead
);
3013 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->Flags
, TRUE
);
3016 // After the repaint operation, we should refresh the highlight.
3021 case CfUiNoOperation
:
3022 ControlFlag
= CfCheckSelection
;
3026 while (gMenuRefreshHead
!= NULL
) {
3027 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
3029 gBS
->FreePool (gMenuRefreshHead
);
3031 gMenuRefreshHead
= OldMenuRefreshEntry
;
3034 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3035 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3036 gST
->ConOut
->OutputString (gST
->ConOut
, (CHAR16
*) L
"\n");
3038 gActiveIfr
= MenuOption
->IfrNumber
;
3049 IN BOOLEAN Direction
,
3050 IN LIST_ENTRY
*CurrentPos
3054 Routine Description:
3055 Determine if the menu is the last menu that can be selected.
3058 Direction - the scroll direction. False is down. True is up.
3061 FALSE -- the menu isn't the last menu that can be selected.
3062 TRUE -- the menu is the last menu that can be selected.
3066 UI_MENU_OPTION
*MenuOption
;
3069 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
3071 if (Temp
== &Menu
) {
3075 for (; Temp
!= &Menu
; Temp
= Direction
? Temp
->BackLink
: Temp
->ForwardLink
) {
3076 MenuOption
= CR (Temp
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3077 if (!(MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
|| MenuOption
->ThisTag
->GrayOut
)) {
3086 AdjustDateAndTimePosition (
3087 IN BOOLEAN DirectionUp
,
3088 IN LIST_ENTRY
**CurrentPosition
3091 Routine Description:
3092 Adjust Data and Time tag position accordingly.
3093 Data format : [01/02/2004] [11:22:33]
3094 Line number : 0 0 1 0 0 1
3097 Direction - the up or down direction. False is down. True is up.
3098 CurrentPos - Current position.
3101 Return line number to pad. It is possible that we stand on a zero-advance
3102 data or time opcode, so pad one line when we judge if we are going to scroll outside.
3106 LIST_ENTRY
*NewPosition
;
3107 UI_MENU_OPTION
*MenuOption
;
3108 UINTN PadLineNumber
;
3111 NewPosition
= *CurrentPosition
;
3112 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3114 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3116 // Calculate the distance from current position to the last Date/Time op-code.
3119 while (MenuOption
->ThisTag
->NumberOfLines
== 0) {
3121 NewPosition
= NewPosition
->ForwardLink
;
3122 MenuOption
= CR (NewPosition
, UI_MENU_OPTION
, Link
, UI_MENU_OPTION_SIGNATURE
);
3126 NewPosition
= *CurrentPosition
;
3129 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
3130 // to be one that back to the previous set of op-codes, we need to advance to the first
3131 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate
3132 // checking can be done.
3134 while (Count
++ < 2) {
3135 NewPosition
= NewPosition
->BackLink
;
3139 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3140 // to be one that progresses to the next set of op-codes, we need to advance to the last
3141 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate
3142 // checking can be done.
3144 while (Count
-- > 0) {
3145 NewPosition
= NewPosition
->ForwardLink
;
3149 *CurrentPosition
= NewPosition
;
3152 return PadLineNumber
;