2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 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.
17 LIST_ENTRY gMenuOption
;
18 LIST_ENTRY gMenuList
= INITIALIZE_LIST_HEAD_VARIABLE (gMenuList
);
19 MENU_REFRESH_ENTRY
*gMenuRefreshHead
; // Menu list used for refresh timer opcode.
20 MENU_REFRESH_ENTRY
*gMenuEventGuidRefreshHead
; // Menu list used for refresh event guid opcode.
23 // Search table for UiDisplayMenu()
25 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
56 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
58 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
102 BOOLEAN GetLineByWidthFinished
= FALSE
;
106 Set Buffer to Value for Size bytes.
108 @param Buffer Memory to set.
109 @param Size Number of bytes to set
110 @param Value Value of the set operation.
123 while ((Size
--) != 0) {
130 Initialize Menu option list.
138 InitializeListHead (&gMenuOption
);
143 Free Menu option linked list.
151 UI_MENU_OPTION
*MenuOption
;
153 while (!IsListEmpty (&gMenuOption
)) {
154 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
155 RemoveEntryList (&MenuOption
->Link
);
158 // We allocated space for this description when we did a GetToken, free it here
160 if (MenuOption
->Skip
!= 0) {
162 // For date/time, MenuOption->Description is shared by three Menu Options
163 // Data format : [01/02/2004] [11:22:33]
164 // Line number : 0 0 1 0 0 1
166 FreePool (MenuOption
->Description
);
168 FreePool (MenuOption
);
174 Create a menu with specified formset GUID and form ID, and add it as a child
175 of the given parent menu.
177 @param Parent The parent of menu to be added.
178 @param HiiHandle Hii handle related to this formset.
179 @param FormSetGuid The Formset Guid of menu to be added.
180 @param FormId The Form ID of menu to be added.
182 @return A pointer to the newly added menu or NULL if memory is insufficient.
187 IN OUT UI_MENU_LIST
*Parent
,
188 IN EFI_HII_HANDLE HiiHandle
,
189 IN EFI_GUID
*FormSetGuid
,
193 UI_MENU_LIST
*MenuList
;
195 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
196 if (MenuList
== NULL
) {
200 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
201 InitializeListHead (&MenuList
->ChildListHead
);
203 MenuList
->HiiHandle
= HiiHandle
;
204 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
205 MenuList
->FormId
= FormId
;
206 MenuList
->Parent
= Parent
;
208 if (Parent
== NULL
) {
210 // If parent is not specified, it is the root Form of a Formset
212 InsertTailList (&gMenuList
, &MenuList
->Link
);
214 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
222 Search Menu with given FormId and FormSetGuid in all cached menu list.
224 @param Parent The parent of menu to search.
225 @param FormSetGuid The Formset GUID of the menu to search.
226 @param FormId The Form ID of menu to search.
228 @return A pointer to menu found or NULL if not found.
232 UiFindChildMenuList (
233 IN UI_MENU_LIST
*Parent
,
234 IN EFI_GUID
*FormSetGuid
,
240 UI_MENU_LIST
*MenuList
;
242 ASSERT (Parent
!= NULL
);
244 if (Parent
->FormId
== FormId
&& CompareGuid (FormSetGuid
, &Parent
->FormSetGuid
)) {
248 Link
= GetFirstNode (&Parent
->ChildListHead
);
249 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
250 Child
= UI_MENU_LIST_FROM_LINK (Link
);
252 MenuList
= UiFindChildMenuList (Child
, FormSetGuid
, FormId
);
253 if (MenuList
!= NULL
) {
257 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
265 Search Menu with given FormSetGuid and FormId in all cached menu list.
267 @param FormSetGuid The Formset GUID of the menu to search.
268 @param FormId The Form ID of menu to search.
270 @return A pointer to menu found or NULL if not found.
275 IN EFI_GUID
*FormSetGuid
,
280 UI_MENU_LIST
*MenuList
;
283 Link
= GetFirstNode (&gMenuList
);
284 while (!IsNull (&gMenuList
, Link
)) {
285 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
287 Child
= UiFindChildMenuList(MenuList
, FormSetGuid
, FormId
);
292 Link
= GetNextNode (&gMenuList
, Link
);
300 Free Menu option linked list.
308 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
310 while (gMenuRefreshHead
!= NULL
) {
311 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
312 FreePool (gMenuRefreshHead
);
313 gMenuRefreshHead
= OldMenuRefreshEntry
;
316 while (gMenuEventGuidRefreshHead
!= NULL
) {
317 OldMenuRefreshEntry
= gMenuEventGuidRefreshHead
->Next
;
318 if (gMenuEventGuidRefreshHead
!= NULL
) {
319 gBS
->CloseEvent(gMenuEventGuidRefreshHead
->Event
);
321 FreePool (gMenuEventGuidRefreshHead
);
322 gMenuEventGuidRefreshHead
= OldMenuRefreshEntry
;
331 @param MenuRefreshEntry Menu refresh structure which has info about the refresh question.
335 IN MENU_REFRESH_ENTRY
*MenuRefreshEntry
338 CHAR16
*OptionString
;
341 UI_MENU_SELECTION
*Selection
;
342 FORM_BROWSER_STATEMENT
*Question
;
344 Selection
= MenuRefreshEntry
->Selection
;
345 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
347 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
348 if (EFI_ERROR (Status
)) {
353 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
355 if (OptionString
!= NULL
) {
357 // If leading spaces on OptionString - remove the spaces
359 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
363 // If old Text is longer than new string, need to clean the old string before paint the newer.
364 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
366 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
367 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
369 MenuRefreshEntry
->CurrentColumn
,
370 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
371 MenuRefreshEntry
->CurrentRow
,
372 MenuRefreshEntry
->CurrentRow
,
373 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
377 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
378 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
379 FreePool (OptionString
);
383 // Question value may be changed, need invoke its Callback()
385 Status
= ProcessCallBackFunction (Selection
, Question
, EFI_BROWSER_ACTION_CHANGING
, FALSE
);
391 Refresh the question which has refresh guid event attribute.
393 @param Event The event which has this function related.
394 @param Context The input context info related to this event or the status code return to the caller.
398 RefreshQuestionNotify(
403 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
404 UI_MENU_SELECTION
*Selection
;
407 // Reset FormPackage update flag
409 mHiiPackageListUpdated
= FALSE
;
411 MenuRefreshEntry
= (MENU_REFRESH_ENTRY
*)Context
;
412 ASSERT (MenuRefreshEntry
!= NULL
);
413 Selection
= MenuRefreshEntry
->Selection
;
415 RefreshQuestion (MenuRefreshEntry
);
417 if (mHiiPackageListUpdated
) {
419 // Package list is updated, force to reparse IFR binary of target Formset
421 mHiiPackageListUpdated
= FALSE
;
422 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
436 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
438 UI_MENU_SELECTION
*Selection
;
440 if (gMenuRefreshHead
!= NULL
) {
442 // call from refresh interval process.
444 MenuRefreshEntry
= gMenuRefreshHead
;
445 Selection
= MenuRefreshEntry
->Selection
;
447 // Reset FormPackage update flag
449 mHiiPackageListUpdated
= FALSE
;
452 Status
= RefreshQuestion (MenuRefreshEntry
);
453 if (EFI_ERROR (Status
)) {
457 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
459 } while (MenuRefreshEntry
!= NULL
);
461 if (mHiiPackageListUpdated
) {
463 // Package list is updated, force to reparse IFR binary of target Formset
465 mHiiPackageListUpdated
= FALSE
;
466 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
476 Wait for a given event to fire, or for an optional timeout to expire.
478 @param Event The event to wait for
479 @param Timeout An optional timeout value in 100 ns units.
480 @param RefreshInterval Menu refresh interval (in seconds).
482 @retval EFI_SUCCESS Event fired before Timeout expired.
483 @retval EFI_TIME_OUT Timout expired before Event fired.
487 UiWaitForSingleEvent (
489 IN UINT64 Timeout
, OPTIONAL
490 IN UINT8 RefreshInterval OPTIONAL
495 EFI_EVENT TimerEvent
;
496 EFI_EVENT WaitList
[2];
500 // Create a timer event
502 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
503 if (!EFI_ERROR (Status
)) {
505 // Set the timer event
514 // Wait for the original event or the timer
517 WaitList
[1] = TimerEvent
;
518 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
519 gBS
->CloseEvent (TimerEvent
);
522 // If the timer expired, change the return to timed out
524 if (!EFI_ERROR (Status
) && Index
== 1) {
525 Status
= EFI_TIMEOUT
;
530 // Update screen every second
532 if (RefreshInterval
== 0) {
533 Timeout
= ONE_SECOND
;
535 Timeout
= RefreshInterval
* ONE_SECOND
;
539 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
542 // Set the timer event
551 // Wait for the original event or the timer
554 WaitList
[1] = TimerEvent
;
555 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
558 // If the timer expired, update anything that needs a refresh and keep waiting
560 if (!EFI_ERROR (Status
) && Index
== 1) {
561 Status
= EFI_TIMEOUT
;
562 if (RefreshInterval
!= 0) {
563 Status
= RefreshForm ();
567 gBS
->CloseEvent (TimerEvent
);
568 } while (Status
== EFI_TIMEOUT
);
576 Add one menu option by specified description and context.
578 @param String String description for this option.
579 @param Handle Hii handle for the package list.
580 @param Form The form this statement belong to.
581 @param Statement Statement of this Menu Option.
582 @param NumberOfLines Display lines for this Menu Option.
583 @param MenuItemCount The index for this Option in the Menu.
585 @retval Pointer Pointer to the added Menu Option.
591 IN EFI_HII_HANDLE Handle
,
592 IN FORM_BROWSER_FORM
*Form
,
593 IN FORM_BROWSER_STATEMENT
*Statement
,
594 IN UINT16 NumberOfLines
,
595 IN UINT16 MenuItemCount
598 UI_MENU_OPTION
*MenuOption
;
605 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
607 // Add three MenuOptions for Date/Time
608 // Data format : [01/02/2004] [11:22:33]
609 // Line number : 0 0 1 0 0 1
614 if (Statement
->Storage
== NULL
) {
616 // For RTC type of date/time, set default refresh interval to be 1 second
618 if (Statement
->RefreshInterval
== 0) {
619 Statement
->RefreshInterval
= 1;
624 for (Index
= 0; Index
< Count
; Index
++) {
625 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
628 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
629 MenuOption
->Description
= String
;
630 MenuOption
->Handle
= Handle
;
631 MenuOption
->ThisTag
= Statement
;
632 MenuOption
->EntryNumber
= MenuItemCount
;
636 // Override LineNumber for the MenuOption in Date/Time sequence
638 MenuOption
->Skip
= 1;
640 MenuOption
->Skip
= NumberOfLines
;
642 MenuOption
->Sequence
= Index
;
644 if (Statement
->GrayOutExpression
!= NULL
) {
645 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
649 // If the form or the question has the lock attribute, deal same as grayout.
651 if (Form
->Locked
|| Statement
->Locked
) {
652 MenuOption
->GrayOut
= TRUE
;
655 switch (Statement
->Operand
) {
656 case EFI_IFR_ORDERED_LIST_OP
:
657 case EFI_IFR_ONE_OF_OP
:
658 case EFI_IFR_NUMERIC_OP
:
659 case EFI_IFR_TIME_OP
:
660 case EFI_IFR_DATE_OP
:
661 case EFI_IFR_CHECKBOX_OP
:
662 case EFI_IFR_PASSWORD_OP
:
663 case EFI_IFR_STRING_OP
:
665 // User could change the value of these items
667 MenuOption
->IsQuestion
= TRUE
;
670 case EFI_IFR_TEXT_OP
:
671 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
673 // Initializing GrayOut option as TRUE for Text setup options
674 // so that those options will be Gray in colour and un selectable.
676 MenuOption
->GrayOut
= TRUE
;
680 MenuOption
->IsQuestion
= FALSE
;
684 if ((Statement
->ValueExpression
!= NULL
) ||
685 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
686 MenuOption
->ReadOnly
= TRUE
;
689 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
697 Routine used to abstract a generic dialog interface and return the selected key or string
699 @param NumberOfLines The number of lines for the dialog box
700 @param HotKey Defines whether a single character is parsed
701 (TRUE) and returned in KeyValue or a string is
702 returned in StringBuffer. Two special characters
703 are considered when entering a string, a SCAN_ESC
704 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
705 string input and returns
706 @param MaximumStringSize The maximum size in bytes of a typed in string
707 (each character is a CHAR16) and the minimum
708 string returned is two bytes
709 @param StringBuffer The passed in pointer to the buffer which will
710 hold the typed in string if HotKey is FALSE
711 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
712 @param ... A series of (quantity == NumberOfLines) text
713 strings which will be used to construct the dialog
716 @retval EFI_SUCCESS Displayed dialog and received user interaction
717 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
718 (StringBuffer == NULL) && (HotKey == FALSE))
719 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
725 IN UINTN NumberOfLines
,
727 IN UINTN MaximumStringSize
,
728 OUT CHAR16
*StringBuffer
,
729 OUT EFI_INPUT_KEY
*KeyValue
,
738 CHAR16
*BufferedString
;
745 BOOLEAN SelectionComplete
;
747 UINTN CurrentAttribute
;
748 UINTN DimensionsWidth
;
749 UINTN DimensionsHeight
;
751 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
752 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
754 SelectionComplete
= FALSE
;
756 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
757 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
758 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
761 ASSERT (BufferedString
);
763 VA_START (Marker
, KeyValue
);
766 // Zero the outgoing buffer
768 ZeroMem (StringBuffer
, MaximumStringSize
);
771 if (KeyValue
== NULL
) {
772 return EFI_INVALID_PARAMETER
;
775 if (StringBuffer
== NULL
) {
776 return EFI_INVALID_PARAMETER
;
782 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
787 // Determine the largest string in the dialog box
788 // Notice we are starting with 1 since String is the first string
790 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
791 StackString
= VA_ARG (Marker
, CHAR16
*);
793 if (StackString
[0] == L
' ') {
794 InputOffset
= Count
+ 1;
797 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
799 // Size of the string visually and subtract the width by one for the null-terminator
801 LargestString
= (GetStringWidth (StackString
) / 2);
806 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
807 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
814 VA_START (Marker
, KeyValue
);
815 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
819 // Take the first key typed and report it back?
822 Status
= WaitForKeyStroke (&Key
);
823 ASSERT_EFI_ERROR (Status
);
824 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
828 Status
= WaitForKeyStroke (&Key
);
830 switch (Key
.UnicodeChar
) {
832 switch (Key
.ScanCode
) {
834 FreePool (TempString
);
835 FreePool (BufferedString
);
836 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
837 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
838 return EFI_DEVICE_ERROR
;
846 case CHAR_CARRIAGE_RETURN
:
847 SelectionComplete
= TRUE
;
848 FreePool (TempString
);
849 FreePool (BufferedString
);
850 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
851 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
856 if (StringBuffer
[0] != CHAR_NULL
) {
857 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
858 TempString
[Index
] = StringBuffer
[Index
];
861 // Effectively truncate string by 1 character
863 TempString
[Index
- 1] = CHAR_NULL
;
864 StrCpy (StringBuffer
, TempString
);
869 // If it is the beginning of the string, don't worry about checking maximum limits
871 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
872 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
873 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
874 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
875 KeyPad
[0] = Key
.UnicodeChar
;
876 KeyPad
[1] = CHAR_NULL
;
877 StrCat (StringBuffer
, KeyPad
);
878 StrCat (TempString
, KeyPad
);
881 // If the width of the input string is now larger than the screen, we nee to
882 // adjust the index to start printing portions of the string
884 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
886 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
888 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
889 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
894 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
895 BufferedString
[Count
] = StringBuffer
[Index
];
898 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
901 } while (!SelectionComplete
);
904 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
905 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
910 Draw a pop up windows based on the dimension, number of lines and
913 @param RequestedWidth The width of the pop-up.
914 @param NumberOfLines The number of lines.
915 @param Marker The variable argument list for the list of string to be printed.
920 IN UINTN RequestedWidth
,
921 IN UINTN NumberOfLines
,
933 UINTN DimensionsWidth
;
934 UINTN DimensionsHeight
;
936 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
937 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
939 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
941 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
942 RequestedWidth
= DimensionsWidth
- 2;
946 // Subtract the PopUp width from total Columns, allow for one space extra on
947 // each end plus a border.
949 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
950 End
= Start
+ RequestedWidth
+ 1;
952 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
953 Bottom
= Top
+ NumberOfLines
+ 2;
955 Character
= BOXDRAW_DOWN_RIGHT
;
956 PrintCharAt (Start
, Top
, Character
);
957 Character
= BOXDRAW_HORIZONTAL
;
958 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
959 PrintChar (Character
);
962 Character
= BOXDRAW_DOWN_LEFT
;
963 PrintChar (Character
);
964 Character
= BOXDRAW_VERTICAL
;
967 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
968 String
= VA_ARG (Marker
, CHAR16
*);
971 // This will clear the background of the line - we never know who might have been
972 // here before us. This differs from the next clear in that it used the non-reverse
973 // video for normal printing.
975 if (GetStringWidth (String
) / 2 > 1) {
976 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
980 // Passing in a space results in the assumption that this is where typing will occur
982 if (String
[0] == L
' ') {
983 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
987 // Passing in a NULL results in a blank space
989 if (String
[0] == CHAR_NULL
) {
990 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
994 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
998 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
999 PrintCharAt (Start
, Index
+ 1, Character
);
1000 PrintCharAt (End
- 1, Index
+ 1, Character
);
1003 Character
= BOXDRAW_UP_RIGHT
;
1004 PrintCharAt (Start
, Bottom
- 1, Character
);
1005 Character
= BOXDRAW_HORIZONTAL
;
1006 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1007 PrintChar (Character
);
1010 Character
= BOXDRAW_UP_LEFT
;
1011 PrintChar (Character
);
1015 Draw a pop up windows based on the dimension, number of lines and
1018 @param RequestedWidth The width of the pop-up.
1019 @param NumberOfLines The number of lines.
1020 @param ... A series of text strings that displayed in the pop-up.
1025 CreateMultiStringPopUp (
1026 IN UINTN RequestedWidth
,
1027 IN UINTN NumberOfLines
,
1033 VA_START (Marker
, NumberOfLines
);
1035 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1042 Update status bar on the bottom of menu.
1044 @param Selection Current Selction info.
1045 @param MessageType The type of message to be shown.
1046 @param Flags The flags in Question header.
1047 @param State Set or clear.
1052 IN UI_MENU_SELECTION
*Selection
,
1053 IN UINTN MessageType
,
1059 CHAR16
*NvUpdateMessage
;
1060 CHAR16
*InputErrorMessage
;
1062 FORM_BROWSER_FORMSET
*LocalFormSet
;
1063 FORM_BROWSER_STATEMENT
*Question
;
1065 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1066 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1068 switch (MessageType
) {
1071 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1073 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1074 gScreenDimensions
.BottomRow
- 1,
1079 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1080 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1081 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1084 mInputError
= FALSE
;
1088 case NV_UPDATE_REQUIRED
:
1090 // Global setting support. Show configuration change on every form.
1093 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1095 if (Selection
!= NULL
&& Selection
->Statement
!= NULL
) {
1096 Question
= Selection
->Statement
;
1097 if (Question
->Storage
!= NULL
|| Question
->Operand
== EFI_IFR_DATE_OP
|| Question
->Operand
== EFI_IFR_TIME_OP
) {
1099 // Update only for Question value that need to be saved into Storage.
1101 Selection
->Form
->NvUpdateRequired
= TRUE
;
1105 if (Selection
== NULL
|| IsNvUpdateRequired (Selection
->FormSet
)) {
1106 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1108 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1109 gScreenDimensions
.BottomRow
- 1,
1114 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1115 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1117 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1118 gScreenDimensions
.BottomRow
- 1,
1125 case REFRESH_STATUS_BAR
:
1127 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1130 switch (gBrowserSettingScope
) {
1133 // Check the maintain list to see whether there is any change.
1135 Link
= GetFirstNode (&gBrowserFormSetList
);
1136 while (!IsNull (&gBrowserFormSetList
, Link
)) {
1137 LocalFormSet
= FORM_BROWSER_FORMSET_FROM_LINK (Link
);
1138 if (IsNvUpdateRequired(LocalFormSet
)) {
1139 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1142 Link
= GetNextNode (&gBrowserFormSetList
, Link
);
1147 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1158 FreePool (InputErrorMessage
);
1159 FreePool (NvUpdateMessage
);
1165 Get the supported width for a particular op-code
1167 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1168 @param Handle The handle in the HII database being used
1170 @return Returns the number of CHAR16 characters that is support.
1175 IN FORM_BROWSER_STATEMENT
*Statement
,
1176 IN EFI_HII_HANDLE Handle
1186 // See if the second text parameter is really NULL
1188 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1189 String
= GetToken (Statement
->TextTwo
, Handle
);
1190 Size
= StrLen (String
);
1194 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1195 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1196 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1197 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1198 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1200 // Allow a wide display if text op-code and no secondary text op-code
1202 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1204 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1206 Width
= (UINT16
) gPromptBlockWidth
;
1209 if (Statement
->InSubtitle
) {
1210 Width
-= SUBTITLE_INDENT
;
1213 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1217 Will copy LineWidth amount of a string in the OutputString buffer and return the
1218 number of CHAR16 characters that were copied into the OutputString buffer.
1220 @param InputString String description for this option.
1221 @param LineWidth Width of the desired string to extract in CHAR16
1223 @param Index Where in InputString to start the copy process
1224 @param OutputString Buffer to copy the string into
1226 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1231 IN CHAR16
*InputString
,
1232 IN UINT16 LineWidth
,
1233 IN OUT UINTN
*Index
,
1234 OUT CHAR16
**OutputString
1240 if (GetLineByWidthFinished
) {
1241 GetLineByWidthFinished
= FALSE
;
1248 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1251 // Ensure we have got a valid buffer
1253 if (*OutputString
!= NULL
) {
1256 //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.
1257 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1259 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1260 *Index
= *Index
+ 2;
1264 // Fast-forward the string and see if there is a carriage-return in the string
1266 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1270 // Copy the desired LineWidth of data to the output buffer.
1271 // Also make sure that we don't copy more than the string.
1272 // Also make sure that if there are linefeeds, we account for them.
1274 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1275 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1278 // Convert to CHAR16 value and show that we are done with this operation
1280 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1281 if (LineWidth
!= 0) {
1282 GetLineByWidthFinished
= TRUE
;
1285 if (Count2
== LineWidth
) {
1287 // Rewind the string from the maximum size until we see a space to break the line
1289 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1291 if (LineWidth
== 0) {
1299 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1302 // If currently pointing to a space, increment the index to the first non-space character
1305 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1309 *Index
= (UINT16
) (*Index
+ LineWidth
);
1318 Update display lines for a Menu Option.
1320 @param Selection The user's selection.
1321 @param MenuOption The MenuOption to be checked.
1325 UpdateOptionSkipLines (
1326 IN UI_MENU_SELECTION
*Selection
,
1327 IN UI_MENU_OPTION
*MenuOption
1334 CHAR16
*OutputString
;
1335 CHAR16
*OptionString
;
1338 OptionString
= NULL
;
1339 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1341 if (OptionString
!= NULL
) {
1342 Width
= (UINT16
) gOptionBlockWidth
;
1346 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1348 // If there is more string to process print on the next row and increment the Skip value
1350 if (StrLen (&OptionString
[Index
]) != 0) {
1353 // Since the Number of lines for this menu entry may or may not be reflected accurately
1354 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1355 // some testing to ensure we are keeping this in-sync.
1357 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1359 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1364 FreePool (OutputString
);
1370 if (OptionString
!= NULL
) {
1371 FreePool (OptionString
);
1377 Check whether this Menu Option could be highlighted.
1379 This is an internal function.
1381 @param MenuOption The MenuOption to be checked.
1383 @retval TRUE This Menu Option is selectable.
1384 @retval FALSE This Menu Option could not be selected.
1389 UI_MENU_OPTION
*MenuOption
1392 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1393 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1402 Determine if the menu is the last menu that can be selected.
1404 This is an internal function.
1406 @param Direction The scroll direction. False is down. True is up.
1407 @param CurrentPos The current focus.
1409 @return FALSE -- the menu isn't the last menu that can be selected.
1410 @return TRUE -- the menu is the last menu that can be selected.
1415 IN BOOLEAN Direction
,
1416 IN LIST_ENTRY
*CurrentPos
1421 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1423 if (Temp
== &gMenuOption
) {
1432 Move to next selectable statement.
1434 This is an internal function.
1436 @param Selection Menu selection.
1437 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1438 @param CurrentPosition Current position.
1439 @param GapToTop Gap position to top or bottom.
1441 @return The row distance from current MenuOption to next selectable MenuOption.
1445 MoveToNextStatement (
1446 IN UI_MENU_SELECTION
*Selection
,
1448 IN OUT LIST_ENTRY
**CurrentPosition
,
1454 UI_MENU_OPTION
*NextMenuOption
;
1455 UI_MENU_OPTION
*PreMenuOption
;
1458 Pos
= *CurrentPosition
;
1459 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1462 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1463 if (NextMenuOption
->Row
== 0) {
1464 UpdateOptionSkipLines (Selection
, NextMenuOption
);
1467 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1469 // Current Position doesn't need to be caculated when go up.
1470 // Caculate distanct at first when go up
1472 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1473 NextMenuOption
= PreMenuOption
;
1476 Distance
+= NextMenuOption
->Skip
;
1478 if (IsSelectable (NextMenuOption
)) {
1481 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1490 // Caculate distanct at later when go down
1492 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1493 NextMenuOption
= PreMenuOption
;
1496 Distance
+= NextMenuOption
->Skip
;
1498 PreMenuOption
= NextMenuOption
;
1499 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1502 *CurrentPosition
= &NextMenuOption
->Link
;
1508 Adjust Data and Time position accordingly.
1509 Data format : [01/02/2004] [11:22:33]
1510 Line number : 0 0 1 0 0 1
1512 This is an internal function.
1514 @param DirectionUp the up or down direction. False is down. True is
1516 @param CurrentPosition Current position. On return: Point to the last
1517 Option (Year or Second) if up; Point to the first
1518 Option (Month or Hour) if down.
1520 @return Return line number to pad. It is possible that we stand on a zero-advance
1521 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1525 AdjustDateAndTimePosition (
1526 IN BOOLEAN DirectionUp
,
1527 IN OUT LIST_ENTRY
**CurrentPosition
1531 LIST_ENTRY
*NewPosition
;
1532 UI_MENU_OPTION
*MenuOption
;
1533 UINTN PadLineNumber
;
1536 NewPosition
= *CurrentPosition
;
1537 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1539 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1540 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1542 // Calculate the distance from current position to the last Date/Time MenuOption
1545 while (MenuOption
->Skip
== 0) {
1547 NewPosition
= NewPosition
->ForwardLink
;
1548 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1552 NewPosition
= *CurrentPosition
;
1555 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1556 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1557 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1558 // checking can be done.
1560 while (Count
++ < 2) {
1561 NewPosition
= NewPosition
->BackLink
;
1565 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1566 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1567 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1568 // checking can be done.
1570 while (Count
-- > 0) {
1571 NewPosition
= NewPosition
->ForwardLink
;
1575 *CurrentPosition
= NewPosition
;
1578 return PadLineNumber
;
1582 Find HII Handle in the HII database associated with given Device Path.
1584 If DevicePath is NULL, then ASSERT.
1586 @param DevicePath Device Path associated with the HII package list
1589 @retval Handle HII package list Handle associated with the Device
1591 @retval NULL Hii Package list handle is not found.
1596 DevicePathToHiiHandle (
1597 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1601 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1606 EFI_HANDLE DriverHandle
;
1607 EFI_HII_HANDLE
*HiiHandles
;
1608 EFI_HII_HANDLE HiiHandle
;
1610 ASSERT (DevicePath
!= NULL
);
1612 TmpDevicePath
= DevicePath
;
1614 // Locate Device Path Protocol handle buffer
1616 Status
= gBS
->LocateDevicePath (
1617 &gEfiDevicePathProtocolGuid
,
1621 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1626 // Retrieve all HII Handles from HII database
1628 BufferSize
= 0x1000;
1629 HiiHandles
= AllocatePool (BufferSize
);
1630 ASSERT (HiiHandles
!= NULL
);
1631 Status
= mHiiDatabase
->ListPackageLists (
1633 EFI_HII_PACKAGE_TYPE_ALL
,
1638 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1639 FreePool (HiiHandles
);
1640 HiiHandles
= AllocatePool (BufferSize
);
1641 ASSERT (HiiHandles
!= NULL
);
1643 Status
= mHiiDatabase
->ListPackageLists (
1645 EFI_HII_PACKAGE_TYPE_ALL
,
1652 if (EFI_ERROR (Status
)) {
1653 FreePool (HiiHandles
);
1658 // Search Hii Handle by Driver Handle
1661 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1662 for (Index
= 0; Index
< HandleCount
; Index
++) {
1663 Status
= mHiiDatabase
->GetPackageListHandle (
1668 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1669 HiiHandle
= HiiHandles
[Index
];
1674 FreePool (HiiHandles
);
1679 Find HII Handle in the HII database associated with given form set guid.
1681 If FormSetGuid is NULL, then ASSERT.
1683 @param ComparingGuid FormSet Guid associated with the HII package list
1686 @retval Handle HII package list Handle associated with the Device
1688 @retval NULL Hii Package list handle is not found.
1692 FormSetGuidToHiiHandle (
1693 EFI_GUID
*ComparingGuid
1696 EFI_HII_HANDLE
*HiiHandles
;
1698 EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
;
1702 UINT32 PackageListLength
;
1703 EFI_HII_PACKAGE_HEADER PackageHeader
;
1707 EFI_HII_HANDLE HiiHandle
;
1709 ASSERT (ComparingGuid
!= NULL
);
1713 // Get all the Hii handles
1715 HiiHandles
= HiiGetHiiHandles (NULL
);
1716 ASSERT (HiiHandles
!= NULL
);
1719 // Search for formset of each class type
1721 for (Index
= 0; HiiHandles
[Index
] != NULL
; Index
++) {
1723 HiiPackageList
= NULL
;
1724 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1725 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1726 HiiPackageList
= AllocatePool (BufferSize
);
1727 ASSERT (HiiPackageList
!= NULL
);
1729 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1731 if (EFI_ERROR (Status
) || HiiPackageList
== NULL
) {
1736 // Get Form package from this HII package List
1738 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
1740 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
1742 while (Offset
< PackageListLength
) {
1743 Package
= ((UINT8
*) HiiPackageList
) + Offset
;
1744 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
1746 if (PackageHeader
.Type
== EFI_HII_PACKAGE_FORMS
) {
1748 // Search FormSet in this Form Package
1750 Offset2
= sizeof (EFI_HII_PACKAGE_HEADER
);
1751 while (Offset2
< PackageHeader
.Length
) {
1752 OpCodeData
= Package
+ Offset2
;
1754 if (((EFI_IFR_OP_HEADER
*) OpCodeData
)->OpCode
== EFI_IFR_FORM_SET_OP
) {
1756 // Try to compare against formset GUID
1758 if (CompareGuid (ComparingGuid
, (EFI_GUID
*)(OpCodeData
+ sizeof (EFI_IFR_OP_HEADER
)))) {
1759 HiiHandle
= HiiHandles
[Index
];
1764 Offset2
+= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
1767 if (HiiHandle
!= NULL
) {
1770 Offset
+= PackageHeader
.Length
;
1773 FreePool (HiiPackageList
);
1774 if (HiiHandle
!= NULL
) {
1779 FreePool (HiiHandles
);
1785 Process the goto op code, update the info in the selection structure.
1787 @param Statement The statement belong to goto op code.
1788 @param Selection The selection info.
1789 @param Repaint Whether need to repaint the menu.
1790 @param NewLine Whether need to create new line.
1792 @retval EFI_SUCCESS The menu process successfully.
1793 @return Other value if the process failed.
1797 IN OUT FORM_BROWSER_STATEMENT
*Statement
,
1798 IN OUT UI_MENU_SELECTION
*Selection
,
1799 OUT BOOLEAN
*Repaint
,
1800 OUT BOOLEAN
*NewLine
1805 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1807 UINT8
*DevicePathBuffer
;
1810 FORM_BROWSER_FORM
*RefForm
;
1813 UI_MENU_LIST
*MenuList
;
1814 BOOLEAN UpdateFormInfo
;
1816 Status
= EFI_SUCCESS
;
1817 UpdateFormInfo
= TRUE
;
1819 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0) {
1820 if (Selection
->Form
->ModalForm
) {
1824 // Goto another Hii Package list
1826 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1828 StringPtr
= GetToken (Statement
->HiiValue
.Value
.ref
.DevicePath
, Selection
->FormSet
->HiiHandle
);
1829 if (StringPtr
== NULL
) {
1831 // No device path string not found, exit
1833 Selection
->Action
= UI_ACTION_EXIT
;
1834 Selection
->Statement
= NULL
;
1837 BufferSize
= StrLen (StringPtr
) / 2;
1838 DevicePath
= AllocatePool (BufferSize
);
1839 ASSERT (DevicePath
!= NULL
);
1842 // Convert from Device Path String to DevicePath Buffer in the reverse order.
1844 DevicePathBuffer
= (UINT8
*) DevicePath
;
1845 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
1846 TemStr
[0] = StringPtr
[Index
];
1847 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
1848 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
1850 // Invalid Hex Char as the tail.
1854 if ((Index
& 1) == 0) {
1855 DevicePathBuffer
[Index
/2] = DigitUint8
;
1857 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
1861 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
1862 if (Selection
->Handle
== NULL
) {
1864 // If target Hii Handle not found, exit
1866 Selection
->Action
= UI_ACTION_EXIT
;
1867 Selection
->Statement
= NULL
;
1871 FreePool (StringPtr
);
1872 FreePool (DevicePath
);
1874 CopyMem (&Selection
->FormSetGuid
,&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1875 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1876 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1877 } else if (!CompareGuid (&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, &gZeroGuid
)) {
1878 if (Selection
->Form
->ModalForm
) {
1882 // Goto another Formset, check for uncommitted data
1884 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1886 Selection
->Handle
= FormSetGuidToHiiHandle(&Statement
->HiiValue
.Value
.ref
.FormSetGuid
);
1887 if (Selection
->Handle
== NULL
) {
1889 // If target Hii Handle not found, exit
1891 Selection
->Action
= UI_ACTION_EXIT
;
1892 Selection
->Statement
= NULL
;
1896 CopyMem (&Selection
->FormSetGuid
, &Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1897 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1898 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1899 } else if (Statement
->HiiValue
.Value
.ref
.FormId
!= 0) {
1901 // Check whether target From is suppressed.
1903 RefForm
= IdToForm (Selection
->FormSet
, Statement
->HiiValue
.Value
.ref
.FormId
);
1905 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
1906 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
1907 if (EFI_ERROR (Status
)) {
1911 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
1913 // Form is suppressed.
1916 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
1917 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1918 if (Repaint
!= NULL
) {
1926 // Goto another form inside this formset,
1928 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1930 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1931 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1932 } else if (Statement
->HiiValue
.Value
.ref
.QuestionId
!= 0) {
1934 // Goto another Question
1936 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1938 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1939 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1941 if (Repaint
!= NULL
) {
1944 if (NewLine
!= NULL
) {
1948 UpdateFormInfo
= FALSE
;
1950 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1951 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1953 UpdateFormInfo
= FALSE
;
1956 if (UpdateFormInfo
) {
1958 // Link current form so that we can always go back when someone hits the ESC
1960 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1961 if (MenuList
== NULL
&& Selection
->CurrentMenu
!= NULL
) {
1962 MenuList
= UiAddMenuList (Selection
->CurrentMenu
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
1970 Display menu and wait for user to select one menu option, then return it.
1971 If AutoBoot is enabled, then if user doesn't select any option,
1972 after period of time, it will automatically return the first menu option.
1974 @param Selection Menu selection.
1976 @retval EFI_SUCESSS This function always return successfully for now.
1981 IN OUT UI_MENU_SELECTION
*Selection
1987 UINTN DistanceValue
;
1999 CHAR16
*OptionString
;
2000 CHAR16
*OutputString
;
2001 CHAR16
*FormattedString
;
2007 BOOLEAN InitializedFlag
;
2012 LIST_ENTRY
*TopOfScreen
;
2013 LIST_ENTRY
*SavedListEntry
;
2014 UI_MENU_OPTION
*MenuOption
;
2015 UI_MENU_OPTION
*NextMenuOption
;
2016 UI_MENU_OPTION
*SavedMenuOption
;
2017 UI_MENU_OPTION
*PreviousMenuOption
;
2018 UI_CONTROL_FLAG ControlFlag
;
2019 EFI_SCREEN_DESCRIPTOR LocalScreen
;
2020 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
2021 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
2022 UI_SCREEN_OPERATION ScreenOperation
;
2023 UINT8 MinRefreshInterval
;
2025 FORM_BROWSER_STATEMENT
*Statement
;
2026 UI_MENU_LIST
*CurrentMenu
;
2027 UINTN ModalSkipColumn
;
2028 BROWSER_HOT_KEY
*HotKey
;
2030 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
2032 Status
= EFI_SUCCESS
;
2033 FormattedString
= NULL
;
2034 OptionString
= NULL
;
2035 ScreenOperation
= UiNoOperation
;
2037 MinRefreshInterval
= 0;
2040 OutputString
= NULL
;
2045 MenuRefreshEntry
= gMenuRefreshHead
;
2047 NextMenuOption
= NULL
;
2048 PreviousMenuOption
= NULL
;
2049 SavedMenuOption
= NULL
;
2051 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
2053 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2055 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
2056 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2057 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2059 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2060 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2063 if (Selection
->Form
->ModalForm
) {
2064 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
2066 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2069 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- gFooterHeight
- SCROLL_ARROW_HEIGHT
- 1;
2071 Selection
->TopRow
= TopRow
;
2072 Selection
->BottomRow
= BottomRow
;
2073 Selection
->PromptCol
= Col
;
2074 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2075 Selection
->Statement
= NULL
;
2077 TopOfScreen
= gMenuOption
.ForwardLink
;
2082 // Find current Menu
2084 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
2085 if (CurrentMenu
== NULL
) {
2087 // Current menu not found, add it to the menu tree
2089 CurrentMenu
= UiAddMenuList (NULL
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
2091 ASSERT (CurrentMenu
!= NULL
);
2092 Selection
->CurrentMenu
= CurrentMenu
;
2094 if (Selection
->QuestionId
== 0) {
2096 // Highlight not specified, fetch it from cached menu
2098 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
2099 Selection
->Sequence
= CurrentMenu
->Sequence
;
2103 // Init option as the current user's selection
2105 InitializedFlag
= TRUE
;
2106 NewPos
= gMenuOption
.ForwardLink
;
2108 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2109 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
2111 ControlFlag
= CfInitialization
;
2112 Selection
->Action
= UI_ACTION_NONE
;
2114 switch (ControlFlag
) {
2115 case CfInitialization
:
2116 if (IsListEmpty (&gMenuOption
)) {
2117 ControlFlag
= CfReadKey
;
2119 ControlFlag
= CfCheckSelection
;
2123 case CfCheckSelection
:
2124 if (Selection
->Action
!= UI_ACTION_NONE
) {
2125 ControlFlag
= CfExit
;
2127 ControlFlag
= CfRepaint
;
2132 ControlFlag
= CfRefreshHighLight
;
2142 Temp
= (UINTN
) SkipValue
;
2143 Temp2
= (UINTN
) SkipValue
;
2145 if (Selection
->Form
->ModalForm
) {
2147 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
2148 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
2149 TopRow
- SCROLL_ARROW_HEIGHT
,
2150 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2151 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2155 LocalScreen
.LeftColumn
,
2156 LocalScreen
.RightColumn
,
2157 TopRow
- SCROLL_ARROW_HEIGHT
,
2158 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2159 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2162 UiFreeRefreshList ();
2163 MinRefreshInterval
= 0;
2165 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2166 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2167 MenuOption
->Row
= Row
;
2168 MenuOption
->Col
= Col
;
2169 if (Selection
->Form
->ModalForm
) {
2170 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
2172 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2175 Statement
= MenuOption
->ThisTag
;
2176 if (Statement
->InSubtitle
) {
2177 MenuOption
->Col
+= SUBTITLE_INDENT
;
2180 if (MenuOption
->GrayOut
) {
2181 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2183 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2184 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2188 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2191 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
2193 // Print Arrow for Goto button.
2196 MenuOption
->Col
- 2,
2199 GEOMETRICSHAPE_RIGHT_TRIANGLE
2203 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2204 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2205 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
2208 // If there is more string to process print on the next row and increment the Skip value
2210 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2216 FreePool (OutputString
);
2225 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2226 if (EFI_ERROR (Status
)) {
2228 // Repaint to clear possible error prompt pop-up
2232 ControlFlag
= CfRepaint
;
2236 if (OptionString
!= NULL
) {
2237 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2239 // If leading spaces on OptionString - remove the spaces
2241 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
2242 MenuOption
->OptCol
++;
2245 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2246 OptionString
[Count
] = OptionString
[Index
];
2250 OptionString
[Count
] = CHAR_NULL
;
2253 Width
= (UINT16
) gOptionBlockWidth
;
2256 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2257 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2258 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2261 // If there is more string to process print on the next row and increment the Skip value
2263 if (StrLen (&OptionString
[Index
]) != 0) {
2267 // Since the Number of lines for this menu entry may or may not be reflected accurately
2268 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2269 // some testing to ensure we are keeping this in-sync.
2271 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2273 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2279 FreePool (OutputString
);
2288 FreePool (OptionString
);
2292 // If Question has refresh guid, register the op-code.
2294 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
2295 if (gMenuEventGuidRefreshHead
== NULL
) {
2296 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2297 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
2299 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
2300 while (MenuUpdateEntry
->Next
!= NULL
) {
2301 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2303 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2304 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2306 ASSERT (MenuUpdateEntry
!= NULL
);
2307 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
2308 ASSERT (!EFI_ERROR (Status
));
2309 MenuUpdateEntry
->MenuOption
= MenuOption
;
2310 MenuUpdateEntry
->Selection
= Selection
;
2311 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
2312 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
2313 if (MenuOption
->GrayOut
) {
2314 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2316 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2321 // If Question request refresh, register the op-code
2323 if (Statement
->RefreshInterval
!= 0) {
2325 // Menu will be refreshed at minimal interval of all Questions
2326 // which have refresh request
2328 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
2329 MinRefreshInterval
= Statement
->RefreshInterval
;
2332 if (gMenuRefreshHead
== NULL
) {
2333 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2334 gMenuRefreshHead
= MenuRefreshEntry
;
2336 MenuRefreshEntry
= gMenuRefreshHead
;
2337 while (MenuRefreshEntry
->Next
!= NULL
) {
2338 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2340 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2341 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2343 ASSERT (MenuRefreshEntry
!= NULL
);
2344 MenuRefreshEntry
->MenuOption
= MenuOption
;
2345 MenuRefreshEntry
->Selection
= Selection
;
2346 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2347 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2348 if (MenuOption
->GrayOut
) {
2349 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2351 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2356 // If this is a text op with secondary text information
2358 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2359 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2361 Width
= (UINT16
) gOptionBlockWidth
;
2364 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
2365 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2366 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2369 // If there is more string to process print on the next row and increment the Skip value
2371 if (StrLen (&StringPtr
[Index
]) != 0) {
2375 // Since the Number of lines for this menu entry may or may not be reflected accurately
2376 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2377 // some testing to ensure we are keeping this in-sync.
2379 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2381 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2387 FreePool (OutputString
);
2394 FreePool (StringPtr
);
2396 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2399 // Need to handle the bottom of the display
2401 if (MenuOption
->Skip
> 1) {
2402 Row
+= MenuOption
->Skip
- SkipValue
;
2405 Row
+= MenuOption
->Skip
;
2408 if (Row
> BottomRow
) {
2409 if (!ValueIsScroll (FALSE
, Link
)) {
2413 Row
= BottomRow
+ 1;
2418 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2423 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2425 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2426 TopRow
- SCROLL_ARROW_HEIGHT
,
2430 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2434 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2436 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2437 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2441 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2448 case CfRefreshHighLight
:
2450 // MenuOption: Last menu option that need to remove hilight
2451 // MenuOption is set to NULL in Repaint
2452 // NewPos: Current menu option that need to hilight
2454 ControlFlag
= CfUpdateHelpString
;
2455 if (InitializedFlag
) {
2456 InitializedFlag
= FALSE
;
2457 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
2461 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2462 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2464 SavedValue
= Repaint
;
2467 if (Selection
->QuestionId
!= 0) {
2468 NewPos
= gMenuOption
.ForwardLink
;
2469 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2471 while ((SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
||
2472 SavedMenuOption
->Sequence
!= Selection
->Sequence
) &&
2473 NewPos
->ForwardLink
!= &gMenuOption
) {
2474 NewPos
= NewPos
->ForwardLink
;
2475 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2477 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2479 // Target Question found, find its MenuOption
2483 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2484 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2485 Index
+= SavedMenuOption
->Skip
;
2486 if (Link
== TopOfScreen
) {
2487 Index
-= OldSkipValue
;
2489 Link
= Link
->ForwardLink
;
2491 if (NewPos
== Link
) {
2492 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2495 if (Link
!= NewPos
|| Index
> BottomRow
|| (Link
== NewPos
&& SavedMenuOption
->Row
+ SavedMenuOption
->Skip
- 1 > BottomRow
)) {
2497 // Find the MenuOption which has the skip value for Date/Time opcode.
2499 AdjustDateAndTimePosition(FALSE
, &NewPos
);
2501 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2503 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2505 // SavedMenuOption->Row == 0 means the menu not show yet.
2507 if (SavedMenuOption
->Row
== 0) {
2508 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2512 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= BottomRow
+ 1; ) {
2513 Link
= Link
->BackLink
;
2514 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2515 if (SavedMenuOption
->Row
== 0) {
2516 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2518 Index
+= SavedMenuOption
->Skip
;
2521 SkipValue
= Index
- BottomRow
- 1;
2522 if (SkipValue
> 0 && SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
2524 OldSkipValue
= SkipValue
;
2527 TopOfScreen
= Link
->ForwardLink
;
2532 ControlFlag
= CfRepaint
;
2537 // Target Question not found, highlight the default menu option
2539 NewPos
= TopOfScreen
;
2542 Selection
->QuestionId
= 0;
2545 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2546 if (MenuOption
!= NULL
) {
2548 // Remove highlight on last Menu Option
2550 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2551 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2552 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2553 if (OptionString
!= NULL
) {
2554 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2555 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2558 // If leading spaces on OptionString - remove the spaces
2560 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2563 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2564 OptionString
[Count
] = OptionString
[Index
];
2568 OptionString
[Count
] = CHAR_NULL
;
2571 Width
= (UINT16
) gOptionBlockWidth
;
2572 OriginalRow
= MenuOption
->Row
;
2574 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2575 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2576 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2579 // If there is more string to process print on the next row and increment the Skip value
2581 if (StrLen (&OptionString
[Index
]) != 0) {
2585 FreePool (OutputString
);
2588 MenuOption
->Row
= OriginalRow
;
2590 FreePool (OptionString
);
2593 if (MenuOption
->GrayOut
) {
2594 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2595 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2596 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2599 OriginalRow
= MenuOption
->Row
;
2600 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2602 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2603 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2604 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2607 // If there is more string to process print on the next row and increment the Skip value
2609 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2613 FreePool (OutputString
);
2616 MenuOption
->Row
= OriginalRow
;
2617 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2623 // This is the current selected statement
2625 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2626 Statement
= MenuOption
->ThisTag
;
2627 Selection
->Statement
= Statement
;
2628 if (!IsSelectable (MenuOption
)) {
2629 Repaint
= SavedValue
;
2630 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2635 // Record highlight for current menu
2637 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2638 CurrentMenu
->Sequence
= MenuOption
->Sequence
;
2641 // Set reverse attribute
2643 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2644 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2647 // Assuming that we have a refresh linked-list created, lets annotate the
2648 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2649 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2651 if (gMenuRefreshHead
!= NULL
) {
2652 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2653 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2654 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2656 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2658 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2659 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2664 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2665 if (OptionString
!= NULL
) {
2666 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2668 // If leading spaces on OptionString - remove the spaces
2670 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2673 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2674 OptionString
[Count
] = OptionString
[Index
];
2678 OptionString
[Count
] = CHAR_NULL
;
2680 Width
= (UINT16
) gOptionBlockWidth
;
2682 OriginalRow
= MenuOption
->Row
;
2684 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2685 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2686 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2689 // If there is more string to process print on the next row and increment the Skip value
2691 if (StrLen (&OptionString
[Index
]) != 0) {
2695 FreePool (OutputString
);
2698 MenuOption
->Row
= OriginalRow
;
2700 FreePool (OptionString
);
2703 OriginalRow
= MenuOption
->Row
;
2705 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2707 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2708 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2709 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2712 // If there is more string to process print on the next row and increment the Skip value
2714 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2718 FreePool (OutputString
);
2721 MenuOption
->Row
= OriginalRow
;
2726 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2729 // Clear reverse attribute
2731 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2734 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2735 // if we didn't break halfway when process CfRefreshHighLight.
2737 Repaint
= SavedValue
;
2740 case CfUpdateHelpString
:
2741 ControlFlag
= CfPrepareToReadKey
;
2742 if (Selection
->Form
->ModalForm
) {
2746 if (Repaint
|| NewLine
) {
2748 // Don't print anything if it is a NULL help token
2750 ASSERT(MenuOption
!= NULL
);
2751 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2754 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2757 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2759 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2761 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2763 // Pad String with spaces to simulate a clearing of the previous line
2765 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2766 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2770 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2772 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2777 // Reset this flag every time we finish using it.
2783 case CfPrepareToReadKey
:
2784 ControlFlag
= CfReadKey
;
2785 ScreenOperation
= UiNoOperation
;
2789 ControlFlag
= CfScreenOperation
;
2792 // Wait for user's selection
2795 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2796 } while (Status
== EFI_TIMEOUT
);
2798 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2800 // IFR is updated in Callback of refresh opcode, re-parse it
2802 ControlFlag
= CfCheckSelection
;
2803 Selection
->Statement
= NULL
;
2807 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2809 // If we encounter error, continue to read another key in.
2811 if (EFI_ERROR (Status
)) {
2812 ControlFlag
= CfReadKey
;
2816 switch (Key
.UnicodeChar
) {
2817 case CHAR_CARRIAGE_RETURN
:
2818 ScreenOperation
= UiSelect
;
2823 // We will push the adjustment of these numeric values directly to the input handler
2824 // NOTE: we won't handle manual input numeric
2829 // If the screen has no menu items, and the user didn't select UiReset
2830 // ignore the selection and go back to reading keys.
2832 if(IsListEmpty (&gMenuOption
)) {
2833 ControlFlag
= CfReadKey
;
2837 ASSERT(MenuOption
!= NULL
);
2838 Statement
= MenuOption
->ThisTag
;
2839 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2840 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2841 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2843 if (Key
.UnicodeChar
== '+') {
2844 gDirection
= SCAN_RIGHT
;
2846 gDirection
= SCAN_LEFT
;
2848 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2849 if (EFI_ERROR (Status
)) {
2851 // Repaint to clear possible error prompt pop-up
2856 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2858 if (OptionString
!= NULL
) {
2859 FreePool (OptionString
);
2865 ScreenOperation
= UiUp
;
2870 ScreenOperation
= UiDown
;
2874 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2876 // If the screen has no menu items, and the user didn't select UiReset
2877 // ignore the selection and go back to reading keys.
2879 if(IsListEmpty (&gMenuOption
)) {
2880 ControlFlag
= CfReadKey
;
2884 ASSERT(MenuOption
!= NULL
);
2885 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2886 ScreenOperation
= UiSelect
;
2892 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2893 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2894 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2899 if (Selection
->Form
->ModalForm
&& (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2901 // ModalForm has no ESC key and Hot Key.
2903 ControlFlag
= CfReadKey
;
2904 } else if (Index
== mScanCodeNumber
) {
2906 // Check whether Key matches the registered hot key.
2909 if ((gBrowserSettingScope
== SystemLevel
) || (gFunctionKeySetting
!= NONE_FUNCTION_KEY_SETTING
)) {
2910 HotKey
= GetHotKeyFromRegisterList (&Key
);
2912 if (HotKey
!= NULL
) {
2913 ScreenOperation
= UiHotKey
;
2920 case CfScreenOperation
:
2921 if (ScreenOperation
!= UiReset
) {
2923 // If the screen has no menu items, and the user didn't select UiReset
2924 // ignore the selection and go back to reading keys.
2926 if (IsListEmpty (&gMenuOption
)) {
2927 ControlFlag
= CfReadKey
;
2933 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2936 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2937 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2944 ControlFlag
= CfCheckSelection
;
2946 ASSERT(MenuOption
!= NULL
);
2947 Statement
= MenuOption
->ThisTag
;
2948 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2953 // Keep highlight on current MenuOption
2955 Selection
->QuestionId
= Statement
->QuestionId
;
2957 switch (Statement
->Operand
) {
2958 case EFI_IFR_REF_OP
:
2959 ProcessGotoOpCode(Statement
, Selection
, &Repaint
, &NewLine
);
2962 case EFI_IFR_ACTION_OP
:
2964 // Process the Config string <ConfigResp>
2966 Status
= ProcessQuestionConfig (Selection
, Statement
);
2968 if (EFI_ERROR (Status
)) {
2973 // The action button may change some Question value, so refresh the form
2975 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2978 case EFI_IFR_RESET_BUTTON_OP
:
2980 // Reset Question to default value specified by DefaultId
2982 ControlFlag
= CfUiDefault
;
2983 DefaultId
= Statement
->DefaultId
;
2988 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2990 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2991 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2993 if (EFI_ERROR (Status
)) {
2996 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2998 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3001 if (OptionString
!= NULL
) {
3002 FreePool (OptionString
);
3010 // We come here when someone press ESC
3012 ControlFlag
= CfCheckSelection
;
3013 FindNextMenu (Selection
, &Repaint
, &NewLine
);
3017 ControlFlag
= CfCheckSelection
;
3018 ASSERT(MenuOption
!= NULL
);
3019 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3020 if (MenuOption
->Sequence
!= 0) {
3022 // In the middle or tail of the Date/Time op-code set, go left.
3024 ASSERT(NewPos
!= NULL
);
3025 NewPos
= NewPos
->BackLink
;
3031 ControlFlag
= CfCheckSelection
;
3032 ASSERT(MenuOption
!= NULL
);
3033 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3034 if (MenuOption
->Sequence
!= 2) {
3036 // In the middle or tail of the Date/Time op-code set, go left.
3038 ASSERT(NewPos
!= NULL
);
3039 NewPos
= NewPos
->ForwardLink
;
3045 ControlFlag
= CfCheckSelection
;
3047 SavedListEntry
= NewPos
;
3049 ASSERT(NewPos
!= NULL
);
3051 // Adjust Date/Time position before we advance forward.
3053 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3054 if (NewPos
->BackLink
!= &gMenuOption
) {
3055 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3056 ASSERT (MenuOption
!= NULL
);
3058 NewPos
= NewPos
->BackLink
;
3060 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3061 if (PreviousMenuOption
->Row
== 0) {
3062 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3064 DistanceValue
= PreviousMenuOption
->Skip
;
3066 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
3067 Difference
= MoveToNextStatement (Selection
, TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
3069 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3071 if (Difference
< 0) {
3073 // We hit the begining MenuOption that can be focused
3074 // so we simply scroll to the top.
3076 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3077 TopOfScreen
= gMenuOption
.ForwardLink
;
3081 // Scroll up to the last page when we have arrived at top page.
3083 NewPos
= &gMenuOption
;
3084 TopOfScreen
= &gMenuOption
;
3085 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3086 ScreenOperation
= UiPageUp
;
3087 ControlFlag
= CfScreenOperation
;
3090 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
3092 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3094 TopOfScreen
= NewPos
;
3098 } else if (!IsSelectable (NextMenuOption
)) {
3100 // Continue to go up until scroll to next page or the selectable option is found.
3102 ScreenOperation
= UiUp
;
3103 ControlFlag
= CfScreenOperation
;
3107 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3109 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3110 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3111 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3112 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3115 // Scroll up to the last page.
3117 NewPos
= &gMenuOption
;
3118 TopOfScreen
= &gMenuOption
;
3119 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3120 ScreenOperation
= UiPageUp
;
3121 ControlFlag
= CfScreenOperation
;
3126 ControlFlag
= CfCheckSelection
;
3128 ASSERT(NewPos
!= NULL
);
3129 if (NewPos
->BackLink
== &gMenuOption
) {
3139 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
3140 Link
= Link
->BackLink
;
3141 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3142 if (PreviousMenuOption
->Row
== 0) {
3143 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3145 if (Index
< PreviousMenuOption
->Skip
) {
3149 Index
= Index
- PreviousMenuOption
->Skip
;
3152 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
3153 if (TopOfScreen
== &gMenuOption
) {
3154 TopOfScreen
= gMenuOption
.ForwardLink
;
3155 NewPos
= gMenuOption
.BackLink
;
3156 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3158 } else if (TopOfScreen
!= Link
) {
3161 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3164 // Finally we know that NewPos is the last MenuOption can be focused.
3168 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3171 if (Index
+ 1 < TopRow
) {
3173 // Back up the previous option.
3175 Link
= Link
->ForwardLink
;
3179 // Move to the option in Next page.
3181 if (TopOfScreen
== &gMenuOption
) {
3182 NewPos
= gMenuOption
.BackLink
;
3183 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3186 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3190 // There are more MenuOption needing scrolling up.
3197 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3198 // Don't do this when we are already in the first page.
3200 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3201 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3205 ControlFlag
= CfCheckSelection
;
3207 ASSERT (NewPos
!= NULL
);
3208 if (NewPos
->ForwardLink
== &gMenuOption
) {
3217 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3219 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
3220 Index
= Index
+ NextMenuOption
->Skip
;
3221 Link
= Link
->ForwardLink
;
3222 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3225 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
3227 // Finally we know that NewPos is the last MenuOption can be focused.
3230 MoveToNextStatement (Selection
, TRUE
, &Link
, Index
- TopRow
);
3232 if (Index
- 1 > BottomRow
) {
3234 // Back up the previous option.
3236 Link
= Link
->BackLink
;
3239 // There are more MenuOption needing scrolling down.
3244 // Move to the option in Next page.
3246 MoveToNextStatement (Selection
, FALSE
, &Link
, BottomRow
- TopRow
);
3250 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3251 // Don't do this when we are already in the last page.
3254 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3255 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3259 ControlFlag
= CfCheckSelection
;
3261 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3262 // to be one that progresses to the next set of op-codes, we need to advance to the last
3263 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3264 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3265 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3266 // the Date/Time op-code.
3268 SavedListEntry
= NewPos
;
3269 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3271 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3272 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3274 NewPos
= NewPos
->ForwardLink
;
3277 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3278 Difference
= MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3280 // We hit the end of MenuOption that can be focused
3281 // so we simply scroll to the first page.
3283 if (Difference
< 0) {
3285 // Scroll to the first page.
3287 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3288 TopOfScreen
= gMenuOption
.ForwardLink
;
3292 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3294 NewPos
= gMenuOption
.ForwardLink
;
3295 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3298 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3300 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3301 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3305 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3308 // An option might be multi-line, so we need to reflect that data in the overall skip value
3310 UpdateOptionSkipLines (Selection
, NextMenuOption
);
3311 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3313 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3314 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3315 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3316 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3322 // If we are going to scroll, update TopOfScreen
3324 if (Temp
> BottomRow
) {
3327 // Is the current top of screen a zero-advance op-code?
3328 // If so, keep moving forward till we hit a >0 advance op-code
3330 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3333 // If bottom op-code is more than one line or top op-code is more than one line
3335 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3337 // Is the bottom op-code greater than or equal in size to the top op-code?
3339 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3341 // Skip the top op-code
3343 TopOfScreen
= TopOfScreen
->ForwardLink
;
3344 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3346 OldSkipValue
= Difference
;
3348 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3351 // If we have a remainder, skip that many more op-codes until we drain the remainder
3353 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3355 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3357 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3358 TopOfScreen
= TopOfScreen
->ForwardLink
;
3359 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3362 // Since we will act on this op-code in the next routine, and increment the
3363 // SkipValue, set the skips to one less than what is required.
3365 SkipValue
= Difference
- 1;
3369 // Since we will act on this op-code in the next routine, and increment the
3370 // SkipValue, set the skips to one less than what is required.
3372 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3375 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3376 TopOfScreen
= TopOfScreen
->ForwardLink
;
3379 SkipValue
= OldSkipValue
;
3383 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3384 // Let's set a skip flag to smoothly scroll the top of the screen.
3386 if (SavedMenuOption
->Skip
> 1) {
3387 if (SavedMenuOption
== NextMenuOption
) {
3392 } else if (SavedMenuOption
->Skip
== 1) {
3396 TopOfScreen
= TopOfScreen
->ForwardLink
;
3398 } while (SavedMenuOption
->Skip
== 0);
3401 OldSkipValue
= SkipValue
;
3402 } else if (!IsSelectable (NextMenuOption
)) {
3404 // Continue to go down until scroll to next page or the selectable option is found.
3406 ScreenOperation
= UiDown
;
3407 ControlFlag
= CfScreenOperation
;
3410 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3412 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3416 // Scroll to the first page.
3418 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3419 TopOfScreen
= gMenuOption
.ForwardLink
;
3423 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3426 NewPos
= gMenuOption
.ForwardLink
;
3427 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3431 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3433 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3434 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3438 ControlFlag
= CfCheckSelection
;
3440 Status
= EFI_SUCCESS
;
3442 // Discard changes. After it, no NV flag is showed.
3444 if ((HotKey
->Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
3445 Status
= DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3446 if (!EFI_ERROR (Status
)) {
3447 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3448 Selection
->Statement
= NULL
;
3449 gResetRequired
= FALSE
;
3452 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDiscardFailed
, gPressEnter
, gEmptyString
);
3453 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3455 // Still show current page.
3457 Selection
->Action
= UI_ACTION_NONE
;
3465 // Reterieve default setting. After it. NV flag will be showed.
3467 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3468 Status
= ExtractDefault (Selection
->FormSet
, Selection
->Form
, HotKey
->DefaultId
, gBrowserSettingScope
);
3469 if (!EFI_ERROR (Status
)) {
3470 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3471 Selection
->Statement
= NULL
;
3472 gResetRequired
= TRUE
;
3475 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDefaultFailed
, gPressEnter
, gEmptyString
);
3476 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3478 // Still show current page.
3480 Selection
->Action
= UI_ACTION_NONE
;
3488 // Save changes. After it, no NV flag is showed.
3490 if ((HotKey
->Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
3491 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3492 if (!EFI_ERROR (Status
)) {
3493 ASSERT(MenuOption
!= NULL
);
3494 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3495 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3498 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3499 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3501 // Still show current page.
3503 Selection
->Action
= UI_ACTION_NONE
;
3511 // Set Reset required Flag
3513 if ((HotKey
->Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
3514 gResetRequired
= TRUE
;
3520 if ((HotKey
->Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
3522 // Form Exit without saving, Similar to ESC Key.
3523 // FormSet Exit without saving, Exit SendForm.
3524 // System Exit without saving, CallExitHandler and Exit SendForm.
3526 DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3527 if (gBrowserSettingScope
== FormLevel
) {
3528 ControlFlag
= CfUiReset
;
3529 } else if (gBrowserSettingScope
== FormSetLevel
) {
3530 Selection
->Action
= UI_ACTION_EXIT
;
3531 } else if (gBrowserSettingScope
== SystemLevel
) {
3532 if (ExitHandlerFunction
!= NULL
) {
3533 ExitHandlerFunction ();
3535 Selection
->Action
= UI_ACTION_EXIT
;
3537 Selection
->Statement
= NULL
;
3542 ControlFlag
= CfCheckSelection
;
3544 // Reset to default value for all forms in the whole system.
3546 Status
= ExtractDefault (Selection
->FormSet
, NULL
, DefaultId
, FormSetLevel
);
3548 if (!EFI_ERROR (Status
)) {
3549 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3550 Selection
->Statement
= NULL
;
3551 gResetRequired
= TRUE
;
3555 case CfUiNoOperation
:
3556 ControlFlag
= CfCheckSelection
;
3560 UiFreeRefreshList ();
3562 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3563 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3564 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3565 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");