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
;
22 // Search table for UiDisplayMenu()
24 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
63 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
111 BOOLEAN GetLineByWidthFinished
= FALSE
;
115 Set Buffer to Value for Size bytes.
117 @param Buffer Memory to set.
118 @param Size Number of bytes to set
119 @param Value Value of the set operation.
132 while ((Size
--) != 0) {
139 Initialize Menu option list.
147 InitializeListHead (&gMenuOption
);
152 Free Menu option linked list.
160 UI_MENU_OPTION
*MenuOption
;
162 while (!IsListEmpty (&gMenuOption
)) {
163 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
164 RemoveEntryList (&MenuOption
->Link
);
167 // We allocated space for this description when we did a GetToken, free it here
169 if (MenuOption
->Skip
!= 0) {
171 // For date/time, MenuOption->Description is shared by three Menu Options
172 // Data format : [01/02/2004] [11:22:33]
173 // Line number : 0 0 1 0 0 1
175 FreePool (MenuOption
->Description
);
177 FreePool (MenuOption
);
183 Create a menu with specified formset GUID and form ID, and add it as a child
184 of the given parent menu.
186 @param Parent The parent of menu to be added.
187 @param FormSetGuid The Formset Guid of menu to be added.
188 @param FormId The Form ID of menu to be added.
190 @return A pointer to the newly added menu or NULL if memory is insufficient.
195 IN OUT UI_MENU_LIST
*Parent
,
196 IN EFI_GUID
*FormSetGuid
,
200 UI_MENU_LIST
*MenuList
;
202 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
203 if (MenuList
== NULL
) {
207 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
208 InitializeListHead (&MenuList
->ChildListHead
);
210 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
211 MenuList
->FormId
= FormId
;
212 MenuList
->Parent
= Parent
;
214 if (Parent
== NULL
) {
216 // If parent is not specified, it is the root Form of a Formset
218 InsertTailList (&gMenuList
, &MenuList
->Link
);
220 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
228 Search Menu with given FormId in the parent menu and all its child menus.
230 @param Parent The parent of menu to search.
231 @param FormId The Form ID of menu to search.
233 @return A pointer to menu found or NULL if not found.
237 UiFindChildMenuList (
238 IN UI_MENU_LIST
*Parent
,
244 UI_MENU_LIST
*MenuList
;
246 if (Parent
->FormId
== FormId
) {
250 Link
= GetFirstNode (&Parent
->ChildListHead
);
251 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
252 Child
= UI_MENU_LIST_FROM_LINK (Link
);
254 MenuList
= UiFindChildMenuList (Child
, FormId
);
255 if (MenuList
!= NULL
) {
259 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
267 Search Menu with given FormSetGuid and FormId in all cached menu list.
269 @param FormSetGuid The Formset GUID of the menu to search.
270 @param FormId The Form ID of menu to search.
272 @return A pointer to menu found or NULL if not found.
277 IN EFI_GUID
*FormSetGuid
,
282 UI_MENU_LIST
*MenuList
;
285 Link
= GetFirstNode (&gMenuList
);
286 while (!IsNull (&gMenuList
, Link
)) {
287 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
289 if (CompareGuid (FormSetGuid
, &MenuList
->FormSetGuid
)) {
291 // This is the formset we are looking for, find the form in this formset
293 Child
= UiFindChildMenuList (MenuList
, FormId
);
299 Link
= GetNextNode (&gMenuList
, Link
);
307 Free Menu option linked list.
315 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
317 while (gMenuRefreshHead
!= NULL
) {
318 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
319 FreePool (gMenuRefreshHead
);
320 gMenuRefreshHead
= OldMenuRefreshEntry
;
323 gMenuRefreshHead
= NULL
;
337 CHAR16
*OptionString
;
338 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
341 UI_MENU_SELECTION
*Selection
;
342 FORM_BROWSER_STATEMENT
*Question
;
343 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
344 EFI_BROWSER_ACTION_REQUEST ActionRequest
;
347 if (gMenuRefreshHead
!= NULL
) {
349 MenuRefreshEntry
= gMenuRefreshHead
;
352 // Reset FormPackage update flag
354 mHiiPackageListUpdated
= FALSE
;
357 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
359 Selection
= MenuRefreshEntry
->Selection
;
360 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
362 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
363 if (EFI_ERROR (Status
)) {
368 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
370 if (OptionString
!= NULL
) {
372 // If leading spaces on OptionString - remove the spaces
374 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
377 PadString
= AllocatePool (gOptionBlockWidth
* sizeof (CHAR16
));
378 SetMem16 (PadString
, (gOptionBlockWidth
- 1) * sizeof (CHAR16
), CHAR_SPACE
);
379 PadString
[gOptionBlockWidth
- 1] = 0;
380 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, PadString
);
381 FreePool (PadString
);
382 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
383 FreePool (OptionString
);
387 // Question value may be changed, need invoke its Callback()
389 ConfigAccess
= Selection
->FormSet
->ConfigAccess
;
390 if (((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) && (ConfigAccess
!= NULL
)) {
391 ActionRequest
= EFI_BROWSER_ACTION_REQUEST_NONE
;
392 Status
= ConfigAccess
->Callback (
394 EFI_BROWSER_ACTION_CHANGING
,
395 Question
->QuestionId
,
396 Question
->HiiValue
.Type
,
397 &Question
->HiiValue
.Value
,
400 if (!EFI_ERROR (Status
)) {
401 switch (ActionRequest
) {
402 case EFI_BROWSER_ACTION_REQUEST_RESET
:
403 gResetRequired
= TRUE
;
406 case EFI_BROWSER_ACTION_REQUEST_SUBMIT
:
407 SubmitForm (Selection
->FormSet
, Selection
->Form
);
410 case EFI_BROWSER_ACTION_REQUEST_EXIT
:
411 Selection
->Action
= UI_ACTION_EXIT
;
412 gNvUpdateRequired
= FALSE
;
421 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
423 } while (MenuRefreshEntry
!= NULL
);
425 if (mHiiPackageListUpdated
) {
427 // Package list is updated, force to reparse IFR binary of target Formset
429 mHiiPackageListUpdated
= FALSE
;
430 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
440 Wait for a given event to fire, or for an optional timeout to expire.
442 @param Event The event to wait for
443 @param Timeout An optional timeout value in 100 ns units.
444 @param RefreshInterval Menu refresh interval (in seconds).
446 @retval EFI_SUCCESS Event fired before Timeout expired.
447 @retval EFI_TIME_OUT Timout expired before Event fired.
451 UiWaitForSingleEvent (
453 IN UINT64 Timeout
, OPTIONAL
454 IN UINT8 RefreshInterval OPTIONAL
459 EFI_EVENT TimerEvent
;
460 EFI_EVENT WaitList
[2];
464 // Create a timer event
466 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
467 if (!EFI_ERROR (Status
)) {
469 // Set the timer event
478 // Wait for the original event or the timer
481 WaitList
[1] = TimerEvent
;
482 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
483 gBS
->CloseEvent (TimerEvent
);
486 // If the timer expired, change the return to timed out
488 if (!EFI_ERROR (Status
) && Index
== 1) {
489 Status
= EFI_TIMEOUT
;
494 // Update screen every second
496 if (RefreshInterval
== 0) {
497 Timeout
= ONE_SECOND
;
499 Timeout
= RefreshInterval
* ONE_SECOND
;
503 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
506 // Set the timer event
515 // Wait for the original event or the timer
518 WaitList
[1] = TimerEvent
;
519 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
522 // If the timer expired, update anything that needs a refresh and keep waiting
524 if (!EFI_ERROR (Status
) && Index
== 1) {
525 Status
= EFI_TIMEOUT
;
526 if (RefreshInterval
!= 0) {
527 Status
= RefreshForm ();
531 gBS
->CloseEvent (TimerEvent
);
532 } while (Status
== EFI_TIMEOUT
);
540 Add one menu option by specified description and context.
542 @param String String description for this option.
543 @param Handle Hii handle for the package list.
544 @param Statement Statement of this Menu Option.
545 @param NumberOfLines Display lines for this Menu Option.
546 @param MenuItemCount The index for this Option in the Menu.
548 @retval Pointer Pointer to the added Menu Option.
554 IN EFI_HII_HANDLE Handle
,
555 IN FORM_BROWSER_STATEMENT
*Statement
,
556 IN UINT16 NumberOfLines
,
557 IN UINT16 MenuItemCount
560 UI_MENU_OPTION
*MenuOption
;
567 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
569 // Add three MenuOptions for Date/Time
570 // Data format : [01/02/2004] [11:22:33]
571 // Line number : 0 0 1 0 0 1
576 if (Statement
->Storage
== NULL
) {
578 // For RTC type of date/time, set default refresh interval to be 1 second
580 if (Statement
->RefreshInterval
== 0) {
581 Statement
->RefreshInterval
= 1;
586 for (Index
= 0; Index
< Count
; Index
++) {
587 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
590 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
591 MenuOption
->Description
= String
;
592 MenuOption
->Handle
= Handle
;
593 MenuOption
->ThisTag
= Statement
;
594 MenuOption
->EntryNumber
= MenuItemCount
;
598 // Override LineNumber for the MenuOption in Date/Time sequence
600 MenuOption
->Skip
= 1;
602 MenuOption
->Skip
= NumberOfLines
;
604 MenuOption
->Sequence
= Index
;
606 if (Statement
->GrayOutExpression
!= NULL
) {
607 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
610 switch (Statement
->Operand
) {
611 case EFI_IFR_ORDERED_LIST_OP
:
612 case EFI_IFR_ONE_OF_OP
:
613 case EFI_IFR_NUMERIC_OP
:
614 case EFI_IFR_TIME_OP
:
615 case EFI_IFR_DATE_OP
:
616 case EFI_IFR_CHECKBOX_OP
:
617 case EFI_IFR_PASSWORD_OP
:
618 case EFI_IFR_STRING_OP
:
620 // User could change the value of these items
622 MenuOption
->IsQuestion
= TRUE
;
626 MenuOption
->IsQuestion
= FALSE
;
630 if ((Statement
->ValueExpression
!= NULL
) ||
631 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
632 MenuOption
->ReadOnly
= TRUE
;
635 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
643 Routine used to abstract a generic dialog interface and return the selected key or string
645 @param NumberOfLines The number of lines for the dialog box
646 @param HotKey Defines whether a single character is parsed
647 (TRUE) and returned in KeyValue or a string is
648 returned in StringBuffer. Two special characters
649 are considered when entering a string, a SCAN_ESC
650 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
651 string input and returns
652 @param MaximumStringSize The maximum size in bytes of a typed in string
653 (each character is a CHAR16) and the minimum
654 string returned is two bytes
655 @param StringBuffer The passed in pointer to the buffer which will
656 hold the typed in string if HotKey is FALSE
657 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
658 @param ... A series of (quantity == NumberOfLines) text
659 strings which will be used to construct the dialog
662 @retval EFI_SUCCESS Displayed dialog and received user interaction
663 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
664 (StringBuffer == NULL) && (HotKey == FALSE))
665 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
671 IN UINTN NumberOfLines
,
673 IN UINTN MaximumStringSize
,
674 OUT CHAR16
*StringBuffer
,
675 OUT EFI_INPUT_KEY
*KeyValue
,
684 CHAR16
*BufferedString
;
691 BOOLEAN SelectionComplete
;
693 UINTN CurrentAttribute
;
694 UINTN DimensionsWidth
;
695 UINTN DimensionsHeight
;
697 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
698 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
700 SelectionComplete
= FALSE
;
702 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
703 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
704 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
707 ASSERT (BufferedString
);
709 VA_START (Marker
, KeyValue
);
712 // Zero the outgoing buffer
714 ZeroMem (StringBuffer
, MaximumStringSize
);
717 if (KeyValue
== NULL
) {
718 return EFI_INVALID_PARAMETER
;
721 if (StringBuffer
== NULL
) {
722 return EFI_INVALID_PARAMETER
;
728 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
733 // Determine the largest string in the dialog box
734 // Notice we are starting with 1 since String is the first string
736 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
737 StackString
= VA_ARG (Marker
, CHAR16
*);
739 if (StackString
[0] == L
' ') {
740 InputOffset
= Count
+ 1;
743 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
745 // Size of the string visually and subtract the width by one for the null-terminator
747 LargestString
= (GetStringWidth (StackString
) / 2);
752 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
753 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
760 VA_START (Marker
, KeyValue
);
761 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
765 // Take the first key typed and report it back?
768 Status
= WaitForKeyStroke (&Key
);
769 ASSERT_EFI_ERROR (Status
);
770 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
774 Status
= WaitForKeyStroke (&Key
);
776 switch (Key
.UnicodeChar
) {
778 switch (Key
.ScanCode
) {
780 FreePool (TempString
);
781 FreePool (BufferedString
);
782 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
783 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
784 return EFI_DEVICE_ERROR
;
792 case CHAR_CARRIAGE_RETURN
:
793 SelectionComplete
= TRUE
;
794 FreePool (TempString
);
795 FreePool (BufferedString
);
796 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
797 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
802 if (StringBuffer
[0] != CHAR_NULL
) {
803 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
804 TempString
[Index
] = StringBuffer
[Index
];
807 // Effectively truncate string by 1 character
809 TempString
[Index
- 1] = CHAR_NULL
;
810 StrCpy (StringBuffer
, TempString
);
815 // If it is the beginning of the string, don't worry about checking maximum limits
817 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
818 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
819 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
820 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
821 KeyPad
[0] = Key
.UnicodeChar
;
822 KeyPad
[1] = CHAR_NULL
;
823 StrCat (StringBuffer
, KeyPad
);
824 StrCat (TempString
, KeyPad
);
827 // If the width of the input string is now larger than the screen, we nee to
828 // adjust the index to start printing portions of the string
830 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
832 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
834 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
835 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
840 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
841 BufferedString
[Count
] = StringBuffer
[Index
];
844 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
847 } while (!SelectionComplete
);
850 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
851 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
856 Draw a pop up windows based on the dimension, number of lines and
859 @param RequestedWidth The width of the pop-up.
860 @param NumberOfLines The number of lines.
861 @param Marker The variable argument list for the list of string to be printed.
866 IN UINTN RequestedWidth
,
867 IN UINTN NumberOfLines
,
879 UINTN DimensionsWidth
;
880 UINTN DimensionsHeight
;
882 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
883 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
885 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
887 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
888 RequestedWidth
= DimensionsWidth
- 2;
892 // Subtract the PopUp width from total Columns, allow for one space extra on
893 // each end plus a border.
895 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
896 End
= Start
+ RequestedWidth
+ 1;
898 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
899 Bottom
= Top
+ NumberOfLines
+ 2;
901 Character
= BOXDRAW_DOWN_RIGHT
;
902 PrintCharAt (Start
, Top
, Character
);
903 Character
= BOXDRAW_HORIZONTAL
;
904 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
905 PrintChar (Character
);
908 Character
= BOXDRAW_DOWN_LEFT
;
909 PrintChar (Character
);
910 Character
= BOXDRAW_VERTICAL
;
913 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
914 String
= VA_ARG (Marker
, CHAR16
*);
917 // This will clear the background of the line - we never know who might have been
918 // here before us. This differs from the next clear in that it used the non-reverse
919 // video for normal printing.
921 if (GetStringWidth (String
) / 2 > 1) {
922 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
926 // Passing in a space results in the assumption that this is where typing will occur
928 if (String
[0] == L
' ') {
929 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
933 // Passing in a NULL results in a blank space
935 if (String
[0] == CHAR_NULL
) {
936 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
940 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
944 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
945 PrintCharAt (Start
, Index
+ 1, Character
);
946 PrintCharAt (End
- 1, Index
+ 1, Character
);
949 Character
= BOXDRAW_UP_RIGHT
;
950 PrintCharAt (Start
, Bottom
- 1, Character
);
951 Character
= BOXDRAW_HORIZONTAL
;
952 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
953 PrintChar (Character
);
956 Character
= BOXDRAW_UP_LEFT
;
957 PrintChar (Character
);
961 Draw a pop up windows based on the dimension, number of lines and
964 @param RequestedWidth The width of the pop-up.
965 @param NumberOfLines The number of lines.
966 @param ... A series of text strings that displayed in the pop-up.
971 CreateMultiStringPopUp (
972 IN UINTN RequestedWidth
,
973 IN UINTN NumberOfLines
,
979 VA_START (Marker
, NumberOfLines
);
981 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
988 Update status bar on the bottom of menu.
990 @param MessageType The type of message to be shown.
991 @param Flags The flags in Question header.
992 @param State Set or clear.
997 IN UINTN MessageType
,
1003 CHAR16
*NvUpdateMessage
;
1004 CHAR16
*InputErrorMessage
;
1006 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1007 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1009 switch (MessageType
) {
1012 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1014 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1015 gScreenDimensions
.BottomRow
- 1,
1020 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1021 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1022 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1025 mInputError
= FALSE
;
1029 case NV_UPDATE_REQUIRED
:
1030 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
1032 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1034 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1035 gScreenDimensions
.BottomRow
- 1,
1038 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1040 gNvUpdateRequired
= TRUE
;
1042 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1043 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1045 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1046 gScreenDimensions
.BottomRow
- 1,
1051 gNvUpdateRequired
= FALSE
;
1056 case REFRESH_STATUS_BAR
:
1058 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
1061 if (gNvUpdateRequired
) {
1062 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1070 FreePool (InputErrorMessage
);
1071 FreePool (NvUpdateMessage
);
1077 Get the supported width for a particular op-code
1079 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1080 @param Handle The handle in the HII database being used
1082 @return Returns the number of CHAR16 characters that is support.
1087 IN FORM_BROWSER_STATEMENT
*Statement
,
1088 IN EFI_HII_HANDLE Handle
1098 // See if the second text parameter is really NULL
1100 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1101 String
= GetToken (Statement
->TextTwo
, Handle
);
1102 Size
= StrLen (String
);
1106 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1107 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1108 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1109 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1110 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1112 // Allow a wide display if text op-code and no secondary text op-code
1114 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1116 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1118 Width
= (UINT16
) gPromptBlockWidth
;
1121 if (Statement
->InSubtitle
) {
1122 Width
-= SUBTITLE_INDENT
;
1125 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1129 Will copy LineWidth amount of a string in the OutputString buffer and return the
1130 number of CHAR16 characters that were copied into the OutputString buffer.
1132 @param InputString String description for this option.
1133 @param LineWidth Width of the desired string to extract in CHAR16
1135 @param Index Where in InputString to start the copy process
1136 @param OutputString Buffer to copy the string into
1138 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1143 IN CHAR16
*InputString
,
1144 IN UINT16 LineWidth
,
1145 IN OUT UINTN
*Index
,
1146 OUT CHAR16
**OutputString
1152 if (GetLineByWidthFinished
) {
1153 GetLineByWidthFinished
= FALSE
;
1160 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1163 // Ensure we have got a valid buffer
1165 if (*OutputString
!= NULL
) {
1168 //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.
1169 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1171 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1172 *Index
= *Index
+ 2;
1176 // Fast-forward the string and see if there is a carriage-return in the string
1178 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1182 // Copy the desired LineWidth of data to the output buffer.
1183 // Also make sure that we don't copy more than the string.
1184 // Also make sure that if there are linefeeds, we account for them.
1186 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1187 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1190 // Convert to CHAR16 value and show that we are done with this operation
1192 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1193 if (LineWidth
!= 0) {
1194 GetLineByWidthFinished
= TRUE
;
1197 if (Count2
== LineWidth
) {
1199 // Rewind the string from the maximum size until we see a space to break the line
1201 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1203 if (LineWidth
== 0) {
1211 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1214 // If currently pointing to a space, increment the index to the first non-space character
1217 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1221 *Index
= (UINT16
) (*Index
+ LineWidth
);
1230 Update display lines for a Menu Option.
1232 @param Selection The user's selection.
1233 @param MenuOption The MenuOption to be checked.
1234 @param OptionalString The option string.
1235 @param SkipValue The number of lins to skip.
1239 UpdateOptionSkipLines (
1240 IN UI_MENU_SELECTION
*Selection
,
1241 IN UI_MENU_OPTION
*MenuOption
,
1242 OUT CHAR16
**OptionalString
,
1250 CHAR16
*OutputString
;
1251 CHAR16
*OptionString
;
1254 OptionString
= *OptionalString
;
1255 OutputString
= NULL
;
1257 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1259 if (OptionString
!= NULL
) {
1260 Width
= (UINT16
) gOptionBlockWidth
;
1264 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1266 // If there is more string to process print on the next row and increment the Skip value
1268 if (StrLen (&OptionString
[Index
]) != 0) {
1269 if (SkipValue
== 0) {
1272 // Since the Number of lines for this menu entry may or may not be reflected accurately
1273 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1274 // some testing to ensure we are keeping this in-sync.
1276 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1278 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1284 FreePool (OutputString
);
1285 if (SkipValue
!= 0) {
1293 *OptionalString
= OptionString
;
1298 Check whether this Menu Option could be highlighted.
1300 This is an internal function.
1302 @param MenuOption The MenuOption to be checked.
1304 @retval TRUE This Menu Option is selectable.
1305 @retval FALSE This Menu Option could not be selected.
1310 UI_MENU_OPTION
*MenuOption
1313 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1314 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1323 Determine if the menu is the last menu that can be selected.
1325 This is an internal function.
1327 @param Direction The scroll direction. False is down. True is up.
1328 @param CurrentPos The current focus.
1330 @return FALSE -- the menu isn't the last menu that can be selected.
1331 @return TRUE -- the menu is the last menu that can be selected.
1336 IN BOOLEAN Direction
,
1337 IN LIST_ENTRY
*CurrentPos
1341 UI_MENU_OPTION
*MenuOption
;
1343 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1345 if (Temp
== &gMenuOption
) {
1349 for (; Temp
!= &gMenuOption
; Temp
= Direction
? Temp
->BackLink
: Temp
->ForwardLink
) {
1350 MenuOption
= MENU_OPTION_FROM_LINK (Temp
);
1351 if (IsSelectable (MenuOption
)) {
1361 Move to next selectable statement.
1363 This is an internal function.
1365 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1366 @param CurrentPosition Current position.
1368 @return The row distance from current MenuOption to next selectable MenuOption.
1372 MoveToNextStatement (
1374 IN OUT LIST_ENTRY
**CurrentPosition
1380 UI_MENU_OPTION
*NextMenuOption
;
1383 Pos
= *CurrentPosition
;
1387 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1388 if (IsSelectable (NextMenuOption
)) {
1391 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1395 Distance
+= NextMenuOption
->Skip
;
1396 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1401 // If we hit end there is still no statement can be focused,
1402 // we go backwards to find the statement can be focused.
1405 Pos
= *CurrentPosition
;
1408 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1409 if (IsSelectable (NextMenuOption
)) {
1412 if ((!GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1416 Distance
-= NextMenuOption
->Skip
;
1417 Pos
= (!GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1421 *CurrentPosition
= &NextMenuOption
->Link
;
1427 Adjust Data and Time position accordingly.
1428 Data format : [01/02/2004] [11:22:33]
1429 Line number : 0 0 1 0 0 1
1431 This is an internal function.
1433 @param DirectionUp the up or down direction. False is down. True is
1435 @param CurrentPosition Current position. On return: Point to the last
1436 Option (Year or Second) if up; Point to the first
1437 Option (Month or Hour) if down.
1439 @return Return line number to pad. It is possible that we stand on a zero-advance
1440 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1444 AdjustDateAndTimePosition (
1445 IN BOOLEAN DirectionUp
,
1446 IN OUT LIST_ENTRY
**CurrentPosition
1450 LIST_ENTRY
*NewPosition
;
1451 UI_MENU_OPTION
*MenuOption
;
1452 UINTN PadLineNumber
;
1455 NewPosition
= *CurrentPosition
;
1456 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1458 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1459 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1461 // Calculate the distance from current position to the last Date/Time MenuOption
1464 while (MenuOption
->Skip
== 0) {
1466 NewPosition
= NewPosition
->ForwardLink
;
1467 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1471 NewPosition
= *CurrentPosition
;
1474 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1475 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1476 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1477 // checking can be done.
1479 while (Count
++ < 2) {
1480 NewPosition
= NewPosition
->BackLink
;
1484 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1485 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1486 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1487 // checking can be done.
1489 while (Count
-- > 0) {
1490 NewPosition
= NewPosition
->ForwardLink
;
1494 *CurrentPosition
= NewPosition
;
1497 return PadLineNumber
;
1501 Find HII Handle in the HII database associated with given Device Path.
1503 If DevicePath is NULL, then ASSERT.
1505 @param DevicePath Device Path associated with the HII package list
1508 @retval Handle HII package list Handle associated with the Device
1510 @retval NULL Hii Package list handle is not found.
1515 DevicePathToHiiHandle (
1516 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1520 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1525 EFI_HANDLE DriverHandle
;
1526 EFI_HII_HANDLE
*HiiHandles
;
1527 EFI_HII_HANDLE HiiHandle
;
1529 ASSERT (DevicePath
!= NULL
);
1531 TmpDevicePath
= DevicePath
;
1533 // Locate Device Path Protocol handle buffer
1535 Status
= gBS
->LocateDevicePath (
1536 &gEfiDevicePathProtocolGuid
,
1540 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1545 // Retrieve all HII Handles from HII database
1547 BufferSize
= 0x1000;
1548 HiiHandles
= AllocatePool (BufferSize
);
1549 ASSERT (HiiHandles
!= NULL
);
1550 Status
= mHiiDatabase
->ListPackageLists (
1552 EFI_HII_PACKAGE_TYPE_ALL
,
1557 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1558 FreePool (HiiHandles
);
1559 HiiHandles
= AllocatePool (BufferSize
);
1560 ASSERT (HiiHandles
!= NULL
);
1562 Status
= mHiiDatabase
->ListPackageLists (
1564 EFI_HII_PACKAGE_TYPE_ALL
,
1571 if (EFI_ERROR (Status
)) {
1572 FreePool (HiiHandles
);
1577 // Search Hii Handle by Driver Handle
1580 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1581 for (Index
= 0; Index
< HandleCount
; Index
++) {
1582 Status
= mHiiDatabase
->GetPackageListHandle (
1587 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1588 HiiHandle
= HiiHandles
[Index
];
1593 FreePool (HiiHandles
);
1598 Display menu and wait for user to select one menu option, then return it.
1599 If AutoBoot is enabled, then if user doesn't select any option,
1600 after period of time, it will automatically return the first menu option.
1602 @param Selection Menu selection.
1604 @retval EFI_SUCESSS This function always return successfully for now.
1609 IN OUT UI_MENU_SELECTION
*Selection
1615 UINTN DistanceValue
;
1627 CHAR16
*OptionString
;
1628 CHAR16
*OutputString
;
1629 CHAR16
*FormattedString
;
1641 LIST_ENTRY
*TopOfScreen
;
1642 LIST_ENTRY
*SavedListEntry
;
1643 UI_MENU_OPTION
*MenuOption
;
1644 UI_MENU_OPTION
*NextMenuOption
;
1645 UI_MENU_OPTION
*SavedMenuOption
;
1646 UI_MENU_OPTION
*PreviousMenuOption
;
1647 UI_CONTROL_FLAG ControlFlag
;
1648 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1649 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1650 UI_SCREEN_OPERATION ScreenOperation
;
1651 UINT8 MinRefreshInterval
;
1654 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1655 FORM_BROWSER_STATEMENT
*Statement
;
1657 UINT8
*DevicePathBuffer
;
1659 UI_MENU_LIST
*CurrentMenu
;
1660 UI_MENU_LIST
*MenuList
;
1661 FORM_BROWSER_FORM
*RefForm
;
1663 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1665 Status
= EFI_SUCCESS
;
1666 FormattedString
= NULL
;
1667 OptionString
= NULL
;
1668 ScreenOperation
= UiNoOperation
;
1670 MinRefreshInterval
= 0;
1673 OutputString
= NULL
;
1678 MenuRefreshEntry
= gMenuRefreshHead
;
1680 NextMenuOption
= NULL
;
1681 PreviousMenuOption
= NULL
;
1682 SavedMenuOption
= NULL
;
1685 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1687 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1688 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1689 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1691 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1692 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1695 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1696 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1698 Selection
->TopRow
= TopRow
;
1699 Selection
->BottomRow
= BottomRow
;
1700 Selection
->PromptCol
= Col
;
1701 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1702 Selection
->Statement
= NULL
;
1704 TopOfScreen
= gMenuOption
.ForwardLink
;
1709 // Find current Menu
1711 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1712 if (CurrentMenu
== NULL
) {
1714 // Current menu not found, add it to the menu tree
1716 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1718 ASSERT (CurrentMenu
!= NULL
);
1720 if (Selection
->QuestionId
== 0) {
1722 // Highlight not specified, fetch it from cached menu
1724 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1728 // Get user's selection
1730 NewPos
= gMenuOption
.ForwardLink
;
1732 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1733 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1735 ControlFlag
= CfInitialization
;
1736 Selection
->Action
= UI_ACTION_NONE
;
1738 switch (ControlFlag
) {
1739 case CfInitialization
:
1740 if (IsListEmpty (&gMenuOption
)) {
1741 ControlFlag
= CfReadKey
;
1743 ControlFlag
= CfCheckSelection
;
1747 case CfCheckSelection
:
1748 if (Selection
->Action
!= UI_ACTION_NONE
) {
1749 ControlFlag
= CfExit
;
1751 ControlFlag
= CfRepaint
;
1756 ControlFlag
= CfRefreshHighLight
;
1766 Temp
= (UINTN
) SkipValue
;
1767 Temp2
= (UINTN
) SkipValue
;
1770 LocalScreen
.LeftColumn
,
1771 LocalScreen
.RightColumn
,
1772 TopRow
- SCROLL_ARROW_HEIGHT
,
1773 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1774 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1777 UiFreeRefreshList ();
1778 MinRefreshInterval
= 0;
1780 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1781 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1782 MenuOption
->Row
= Row
;
1783 MenuOption
->Col
= Col
;
1784 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1786 Statement
= MenuOption
->ThisTag
;
1787 if (Statement
->InSubtitle
) {
1788 MenuOption
->Col
+= SUBTITLE_INDENT
;
1791 if (MenuOption
->GrayOut
) {
1792 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1794 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1795 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
1799 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1802 if (Statement
->Operand
== EFI_IFR_REF_OP
&&
1803 MenuOption
->Col
>= 2) {
1805 // Print Arrow for Goto button.
1808 MenuOption
->Col
- 2,
1811 GEOMETRICSHAPE_RIGHT_TRIANGLE
1815 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1816 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1817 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1820 // If there is more string to process print on the next row and increment the Skip value
1822 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1828 FreePool (OutputString
);
1837 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1838 if (EFI_ERROR (Status
)) {
1840 // Repaint to clear possible error prompt pop-up
1844 ControlFlag
= CfRepaint
;
1848 if (OptionString
!= NULL
) {
1849 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1851 // If leading spaces on OptionString - remove the spaces
1853 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1854 MenuOption
->OptCol
++;
1857 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1858 OptionString
[Count
] = OptionString
[Index
];
1862 OptionString
[Count
] = CHAR_NULL
;
1866 // If Question request refresh, register the op-code
1868 if (Statement
->RefreshInterval
!= 0) {
1870 // Menu will be refreshed at minimal interval of all Questions
1871 // which have refresh request
1873 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1874 MinRefreshInterval
= Statement
->RefreshInterval
;
1877 if (gMenuRefreshHead
== NULL
) {
1878 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1879 ASSERT (MenuRefreshEntry
!= NULL
);
1880 MenuRefreshEntry
->MenuOption
= MenuOption
;
1881 MenuRefreshEntry
->Selection
= Selection
;
1882 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1883 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1884 if (MenuOption
->GrayOut
) {
1885 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1887 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1889 gMenuRefreshHead
= MenuRefreshEntry
;
1892 // Advance to the last entry
1894 for (MenuRefreshEntry
= gMenuRefreshHead
;
1895 MenuRefreshEntry
->Next
!= NULL
;
1896 MenuRefreshEntry
= MenuRefreshEntry
->Next
1899 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1900 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1901 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1902 MenuRefreshEntry
->MenuOption
= MenuOption
;
1903 MenuRefreshEntry
->Selection
= Selection
;
1904 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1905 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1906 if (MenuOption
->GrayOut
) {
1907 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1909 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1914 Width
= (UINT16
) gOptionBlockWidth
;
1917 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1918 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1919 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1922 // If there is more string to process print on the next row and increment the Skip value
1924 if (StrLen (&OptionString
[Index
]) != 0) {
1928 // Since the Number of lines for this menu entry may or may not be reflected accurately
1929 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1930 // some testing to ensure we are keeping this in-sync.
1932 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1934 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1940 FreePool (OutputString
);
1949 FreePool (OptionString
);
1952 // If this is a text op with secondary text information
1954 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1955 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
1957 Width
= (UINT16
) gOptionBlockWidth
;
1960 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1961 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1962 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1965 // If there is more string to process print on the next row and increment the Skip value
1967 if (StrLen (&StringPtr
[Index
]) != 0) {
1971 // Since the Number of lines for this menu entry may or may not be reflected accurately
1972 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1973 // some testing to ensure we are keeping this in-sync.
1975 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1977 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1983 FreePool (OutputString
);
1990 FreePool (StringPtr
);
1992 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
1995 // Need to handle the bottom of the display
1997 if (MenuOption
->Skip
> 1) {
1998 Row
+= MenuOption
->Skip
- SkipValue
;
2001 Row
+= MenuOption
->Skip
;
2004 if (Row
> BottomRow
) {
2005 if (!ValueIsScroll (FALSE
, Link
)) {
2009 Row
= BottomRow
+ 1;
2014 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2019 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2021 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2022 TopRow
- SCROLL_ARROW_HEIGHT
,
2026 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2030 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2032 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2033 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2037 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2044 case CfRefreshHighLight
:
2046 // MenuOption: Last menu option that need to remove hilight
2047 // MenuOption is set to NULL in Repaint
2048 // NewPos: Current menu option that need to hilight
2050 ControlFlag
= CfUpdateHelpString
;
2053 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2054 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2056 SavedValue
= Repaint
;
2059 if (Selection
->QuestionId
!= 0) {
2060 NewPos
= gMenuOption
.ForwardLink
;
2061 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2063 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &gMenuOption
) {
2064 NewPos
= NewPos
->ForwardLink
;
2065 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2067 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2069 // Target Question found, find its MenuOption
2073 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2074 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2075 Index
+= SavedMenuOption
->Skip
;
2076 Link
= Link
->ForwardLink
;
2079 if (Link
!= NewPos
|| Index
> BottomRow
) {
2081 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2084 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2085 Link
= Link
->BackLink
;
2086 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2087 Index
+= SavedMenuOption
->Skip
;
2089 TopOfScreen
= Link
->ForwardLink
;
2093 ControlFlag
= CfRepaint
;
2098 // Target Question not found, highlight the default menu option
2100 NewPos
= TopOfScreen
;
2103 Selection
->QuestionId
= 0;
2106 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2107 if (MenuOption
!= NULL
) {
2109 // Remove highlight on last Menu Option
2111 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2112 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2113 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2114 if (OptionString
!= NULL
) {
2115 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2116 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2119 // If leading spaces on OptionString - remove the spaces
2121 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2124 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2125 OptionString
[Count
] = OptionString
[Index
];
2129 OptionString
[Count
] = CHAR_NULL
;
2132 Width
= (UINT16
) gOptionBlockWidth
;
2133 OriginalRow
= MenuOption
->Row
;
2135 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2136 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2137 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2140 // If there is more string to process print on the next row and increment the Skip value
2142 if (StrLen (&OptionString
[Index
]) != 0) {
2146 FreePool (OutputString
);
2149 MenuOption
->Row
= OriginalRow
;
2151 FreePool (OptionString
);
2154 if (MenuOption
->GrayOut
) {
2155 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2156 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2157 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2160 OriginalRow
= MenuOption
->Row
;
2161 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2163 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2164 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2165 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2168 // If there is more string to process print on the next row and increment the Skip value
2170 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2174 FreePool (OutputString
);
2177 MenuOption
->Row
= OriginalRow
;
2178 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2184 // This is only possible if we entered this page and the first menu option is
2185 // a "non-menu" item. In that case, force it UiDown
2187 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2188 if (!IsSelectable (MenuOption
)) {
2189 ASSERT (ScreenOperation
== UiNoOperation
);
2190 ScreenOperation
= UiDown
;
2191 ControlFlag
= CfScreenOperation
;
2196 // This is the current selected statement
2198 Statement
= MenuOption
->ThisTag
;
2199 Selection
->Statement
= Statement
;
2201 // Record highlight for current menu
2203 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2206 // Set reverse attribute
2208 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2209 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2212 // Assuming that we have a refresh linked-list created, lets annotate the
2213 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2214 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2216 if (gMenuRefreshHead
!= NULL
) {
2217 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2218 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2219 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2221 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2223 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2224 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2229 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2230 if (OptionString
!= NULL
) {
2231 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2233 // If leading spaces on OptionString - remove the spaces
2235 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2238 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2239 OptionString
[Count
] = OptionString
[Index
];
2243 OptionString
[Count
] = CHAR_NULL
;
2245 Width
= (UINT16
) gOptionBlockWidth
;
2247 OriginalRow
= MenuOption
->Row
;
2249 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2250 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2251 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2254 // If there is more string to process print on the next row and increment the Skip value
2256 if (StrLen (&OptionString
[Index
]) != 0) {
2260 FreePool (OutputString
);
2263 MenuOption
->Row
= OriginalRow
;
2265 FreePool (OptionString
);
2268 OriginalRow
= MenuOption
->Row
;
2270 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2272 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2273 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2274 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2277 // If there is more string to process print on the next row and increment the Skip value
2279 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2283 FreePool (OutputString
);
2286 MenuOption
->Row
= OriginalRow
;
2291 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2294 // Clear reverse attribute
2296 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2299 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2300 // if we didn't break halfway when process CfRefreshHighLight.
2302 Repaint
= SavedValue
;
2305 case CfUpdateHelpString
:
2306 ControlFlag
= CfPrepareToReadKey
;
2308 if (Repaint
|| NewLine
) {
2310 // Don't print anything if it is a NULL help token
2312 ASSERT(MenuOption
!= NULL
);
2313 if (MenuOption
->ThisTag
->Help
== 0) {
2316 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2319 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2321 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2323 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2325 // Pad String with spaces to simulate a clearing of the previous line
2327 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2328 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2332 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2334 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2339 // Reset this flag every time we finish using it.
2345 case CfPrepareToReadKey
:
2346 ControlFlag
= CfReadKey
;
2347 ScreenOperation
= UiNoOperation
;
2351 ControlFlag
= CfScreenOperation
;
2354 // Wait for user's selection
2357 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2358 } while (Status
== EFI_TIMEOUT
);
2360 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2362 // IFR is updated in Callback of refresh opcode, re-parse it
2364 Selection
->Statement
= NULL
;
2368 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2370 // If we encounter error, continue to read another key in.
2372 if (EFI_ERROR (Status
)) {
2373 ControlFlag
= CfReadKey
;
2377 switch (Key
.UnicodeChar
) {
2378 case CHAR_CARRIAGE_RETURN
:
2379 ScreenOperation
= UiSelect
;
2384 // We will push the adjustment of these numeric values directly to the input handler
2385 // NOTE: we won't handle manual input numeric
2390 // If the screen has no menu items, and the user didn't select UiReset
2391 // ignore the selection and go back to reading keys.
2393 if(IsListEmpty (&gMenuOption
)) {
2394 ControlFlag
= CfReadKey
;
2398 ASSERT(MenuOption
!= NULL
);
2399 Statement
= MenuOption
->ThisTag
;
2400 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2401 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2402 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2404 if (Key
.UnicodeChar
== '+') {
2405 gDirection
= SCAN_RIGHT
;
2407 gDirection
= SCAN_LEFT
;
2409 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2410 if (EFI_ERROR (Status
)) {
2412 // Repaint to clear possible error prompt pop-up
2417 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2419 if (OptionString
!= NULL
) {
2420 FreePool (OptionString
);
2426 ScreenOperation
= UiUp
;
2431 ScreenOperation
= UiDown
;
2435 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2437 // If the screen has no menu items, and the user didn't select UiReset
2438 // ignore the selection and go back to reading keys.
2440 if(IsListEmpty (&gMenuOption
)) {
2441 ControlFlag
= CfReadKey
;
2445 ASSERT(MenuOption
!= NULL
);
2446 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2447 ScreenOperation
= UiSelect
;
2453 if (((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2454 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2457 // If the function key has been disabled, just ignore the key.
2460 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2461 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2462 if (Key
.ScanCode
== SCAN_F9
) {
2464 // Reset to standard default
2466 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2468 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2477 case CfScreenOperation
:
2478 if (ScreenOperation
!= UiReset
) {
2480 // If the screen has no menu items, and the user didn't select UiReset
2481 // ignore the selection and go back to reading keys.
2483 if (IsListEmpty (&gMenuOption
)) {
2484 ControlFlag
= CfReadKey
;
2488 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2490 for (Link
= gMenuOption
.ForwardLink
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2491 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2492 if (IsSelectable (NextMenuOption
)) {
2497 if (Link
== &gMenuOption
) {
2498 ControlFlag
= CfPrepareToReadKey
;
2504 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2507 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2508 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2515 ControlFlag
= CfCheckSelection
;
2517 ASSERT(MenuOption
!= NULL
);
2518 Statement
= MenuOption
->ThisTag
;
2519 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2524 // Keep highlight on current MenuOption
2526 Selection
->QuestionId
= Statement
->QuestionId
;
2528 switch (Statement
->Operand
) {
2529 case EFI_IFR_REF_OP
:
2530 if (Statement
->RefDevicePath
!= 0) {
2532 // Goto another Hii Package list
2534 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2536 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2537 if (StringPtr
== NULL
) {
2539 // No device path string not found, exit
2541 Selection
->Action
= UI_ACTION_EXIT
;
2542 Selection
->Statement
= NULL
;
2545 BufferSize
= StrLen (StringPtr
) / 2;
2546 DevicePath
= AllocatePool (BufferSize
);
2547 ASSERT (DevicePath
!= NULL
);
2550 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2552 DevicePathBuffer
= (UINT8
*) DevicePath
;
2553 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2554 TemStr
[0] = StringPtr
[Index
];
2555 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2556 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2558 // Invalid Hex Char as the tail.
2562 if ((Index
& 1) == 0) {
2563 DevicePathBuffer
[Index
/2] = DigitUint8
;
2565 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2569 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2570 if (Selection
->Handle
== NULL
) {
2572 // If target Hii Handle not found, exit
2574 Selection
->Action
= UI_ACTION_EXIT
;
2575 Selection
->Statement
= NULL
;
2579 FreePool (StringPtr
);
2580 FreePool (DevicePath
);
2582 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2583 Selection
->FormId
= Statement
->RefFormId
;
2584 Selection
->QuestionId
= Statement
->RefQuestionId
;
2585 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2587 // Goto another Formset, check for uncommitted data
2589 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2591 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2592 Selection
->FormId
= Statement
->RefFormId
;
2593 Selection
->QuestionId
= Statement
->RefQuestionId
;
2594 } else if (Statement
->RefFormId
!= 0) {
2596 // Check whether target From is suppressed.
2598 RefForm
= IdToForm (Selection
->FormSet
, Statement
->RefFormId
);
2600 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2601 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
2602 if (EFI_ERROR (Status
)) {
2606 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
2608 // Form is suppressed.
2611 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2612 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2620 // Goto another form inside this formset,
2622 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2625 // Link current form so that we can always go back when someone hits the ESC
2627 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->RefFormId
);
2628 if (MenuList
== NULL
) {
2629 MenuList
= UiAddMenuList (CurrentMenu
, &Selection
->FormSetGuid
, Statement
->RefFormId
);
2632 Selection
->FormId
= Statement
->RefFormId
;
2633 Selection
->QuestionId
= Statement
->RefQuestionId
;
2634 } else if (Statement
->RefQuestionId
!= 0) {
2636 // Goto another Question
2638 Selection
->QuestionId
= Statement
->RefQuestionId
;
2640 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2641 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2650 case EFI_IFR_ACTION_OP
:
2652 // Process the Config string <ConfigResp>
2654 Status
= ProcessQuestionConfig (Selection
, Statement
);
2656 if (EFI_ERROR (Status
)) {
2661 // The action button may change some Question value, so refresh the form
2663 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2666 case EFI_IFR_RESET_BUTTON_OP
:
2668 // Reset Question to default value specified by DefaultId
2670 ControlFlag
= CfUiDefault
;
2671 DefaultId
= Statement
->DefaultId
;
2676 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2678 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2679 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2681 if (EFI_ERROR (Status
)) {
2684 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2686 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2689 if (OptionString
!= NULL
) {
2690 FreePool (OptionString
);
2698 // We come here when someone press ESC
2700 ControlFlag
= CfCheckSelection
;
2702 if (CurrentMenu
->Parent
!= NULL
) {
2704 // we have a parent, so go to the parent menu
2706 if (CompareGuid (&CurrentMenu
->FormSetGuid
, &CurrentMenu
->Parent
->FormSetGuid
)) {
2708 // The parent menu and current menu are in the same formset
2710 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2712 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2714 Selection
->Statement
= NULL
;
2716 Selection
->FormId
= CurrentMenu
->Parent
->FormId
;
2717 Selection
->QuestionId
= CurrentMenu
->Parent
->QuestionId
;
2720 // Clear highlight record for this menu
2722 CurrentMenu
->QuestionId
= 0;
2726 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
) {
2728 // We never exit FrontPage, so skip the ESC
2730 Selection
->Action
= UI_ACTION_NONE
;
2735 // We are going to leave current FormSet, so check uncommited data in this FormSet
2737 if (gNvUpdateRequired
) {
2738 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2740 YesResponse
= gYesResponse
[0];
2741 NoResponse
= gNoResponse
[0];
2744 // If NV flag is up, prompt user
2747 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveChanges
, gAreYouSure
, gEmptyString
);
2750 (Key
.ScanCode
!= SCAN_ESC
) &&
2751 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2752 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2755 if (Key
.ScanCode
== SCAN_ESC
) {
2757 // User hits the ESC key
2762 Selection
->Action
= UI_ACTION_NONE
;
2767 // If the user hits the YesResponse key
2769 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2770 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
);
2774 Selection
->Action
= UI_ACTION_EXIT
;
2775 Selection
->Statement
= NULL
;
2776 CurrentMenu
->QuestionId
= 0;
2781 ControlFlag
= CfCheckSelection
;
2782 ASSERT(MenuOption
!= NULL
);
2783 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2784 if (MenuOption
->Sequence
!= 0) {
2786 // In the middle or tail of the Date/Time op-code set, go left.
2788 ASSERT(NewPos
!= NULL
);
2789 NewPos
= NewPos
->BackLink
;
2795 ControlFlag
= CfCheckSelection
;
2796 ASSERT(MenuOption
!= NULL
);
2797 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2798 if (MenuOption
->Sequence
!= 2) {
2800 // In the middle or tail of the Date/Time op-code set, go left.
2802 ASSERT(NewPos
!= NULL
);
2803 NewPos
= NewPos
->ForwardLink
;
2809 ControlFlag
= CfCheckSelection
;
2811 SavedListEntry
= TopOfScreen
;
2813 ASSERT(NewPos
!= NULL
);
2814 if (NewPos
->BackLink
!= &gMenuOption
) {
2817 // Adjust Date/Time position before we advance forward.
2819 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2822 // Caution that we have already rewind to the top, don't go backward in this situation.
2824 if (NewPos
->BackLink
!= &gMenuOption
) {
2825 NewPos
= NewPos
->BackLink
;
2828 Difference
= MoveToNextStatement (TRUE
, &NewPos
);
2829 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2830 DistanceValue
= PreviousMenuOption
->Skip
;
2833 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2834 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2835 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2836 // checking can be done.
2838 DistanceValue
+= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2840 ASSERT (MenuOption
!= NULL
);
2841 if (Difference
< 0) {
2843 // We want to goto previous MenuOption, but finally we go down.
2844 // it means that we hit the begining MenuOption that can be focused
2845 // so we simply scroll to the top
2847 if (SavedListEntry
!= gMenuOption
.ForwardLink
) {
2848 TopOfScreen
= gMenuOption
.ForwardLink
;
2851 } else if ((INTN
) MenuOption
->Row
- (INTN
) DistanceValue
- Difference
< (INTN
) TopRow
) {
2853 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2855 TopOfScreen
= NewPos
;
2862 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2864 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2866 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2868 SavedMenuOption
= MenuOption
;
2869 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2870 if (!IsSelectable (MenuOption
)) {
2872 // If we are at the end of the list and sitting on a text op, we need to more forward
2874 ScreenOperation
= UiDown
;
2875 ControlFlag
= CfScreenOperation
;
2879 MenuOption
= SavedMenuOption
;
2884 ControlFlag
= CfCheckSelection
;
2886 ASSERT(NewPos
!= NULL
);
2887 if (NewPos
->BackLink
== &gMenuOption
) {
2896 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2898 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2899 Index
= Index
- PreviousMenuOption
->Skip
;
2900 Link
= Link
->BackLink
;
2901 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2905 Difference
= MoveToNextStatement (TRUE
, &Link
);
2906 if (Difference
> 0) {
2908 // The focus MenuOption is above the TopOfScreen
2911 } else if (Difference
< 0) {
2913 // This happens when there is no MenuOption can be focused from
2914 // Current MenuOption to the first MenuOption
2916 TopOfScreen
= gMenuOption
.ForwardLink
;
2918 Index
+= Difference
;
2919 if (Index
< TopRow
) {
2923 if (NewPos
== Link
) {
2931 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2932 // Don't do this when we are already in the first page.
2934 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2935 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2939 ControlFlag
= CfCheckSelection
;
2941 ASSERT (NewPos
!= NULL
);
2942 if (NewPos
->ForwardLink
== &gMenuOption
) {
2951 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2953 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
2954 Index
= Index
+ NextMenuOption
->Skip
;
2955 Link
= Link
->ForwardLink
;
2956 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2959 Index
+= MoveToNextStatement (FALSE
, &Link
);
2960 if (Index
> BottomRow
) {
2962 // There are more MenuOption needing scrolling
2967 if (NewPos
== Link
&& Index
<= BottomRow
) {
2969 // Finally we know that NewPos is the last MenuOption can be focused.
2978 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2979 // Don't do this when we are already in the last page.
2981 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2982 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2986 ControlFlag
= CfCheckSelection
;
2988 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2989 // to be one that progresses to the next set of op-codes, we need to advance to the last
2990 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2991 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2992 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2993 // the Date/Time op-code.
2995 SavedListEntry
= NewPos
;
2996 DistanceValue
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2998 if (NewPos
->ForwardLink
!= &gMenuOption
) {
2999 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3001 NewPos
= NewPos
->ForwardLink
;
3003 DistanceValue
+= MoveToNextStatement (FALSE
, &NewPos
);
3004 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3007 // An option might be multi-line, so we need to reflect that data in the overall skip value
3009 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
3010 DistanceValue
+= NextMenuOption
->Skip
;
3012 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3013 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3014 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3015 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3021 // If we are going to scroll, update TopOfScreen
3023 if (Temp
> BottomRow
) {
3026 // Is the current top of screen a zero-advance op-code?
3027 // If so, keep moving forward till we hit a >0 advance op-code
3029 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3032 // If bottom op-code is more than one line or top op-code is more than one line
3034 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3036 // Is the bottom op-code greater than or equal in size to the top op-code?
3038 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3040 // Skip the top op-code
3042 TopOfScreen
= TopOfScreen
->ForwardLink
;
3043 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3045 OldSkipValue
= Difference
;
3047 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3050 // If we have a remainder, skip that many more op-codes until we drain the remainder
3052 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3054 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3056 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3057 TopOfScreen
= TopOfScreen
->ForwardLink
;
3058 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3061 // Since we will act on this op-code in the next routine, and increment the
3062 // SkipValue, set the skips to one less than what is required.
3064 SkipValue
= Difference
- 1;
3068 // Since we will act on this op-code in the next routine, and increment the
3069 // SkipValue, set the skips to one less than what is required.
3071 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3074 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3075 TopOfScreen
= TopOfScreen
->ForwardLink
;
3078 SkipValue
= OldSkipValue
;
3082 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3083 // Let's set a skip flag to smoothly scroll the top of the screen.
3085 if (SavedMenuOption
->Skip
> 1) {
3086 if (SavedMenuOption
== NextMenuOption
) {
3091 } else if (SavedMenuOption
->Skip
== 1) {
3095 TopOfScreen
= TopOfScreen
->ForwardLink
;
3097 } while (SavedMenuOption
->Skip
== 0);
3100 OldSkipValue
= SkipValue
;
3103 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3105 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3108 SavedMenuOption
= MenuOption
;
3109 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3110 if (!IsSelectable (MenuOption
)) {
3112 // If we are at the end of the list and sitting on a text op, we need to more forward
3114 ScreenOperation
= UiUp
;
3115 ControlFlag
= CfScreenOperation
;
3119 MenuOption
= SavedMenuOption
;
3121 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3123 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3128 ControlFlag
= CfCheckSelection
;
3133 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
);
3135 if (!EFI_ERROR (Status
)) {
3136 ASSERT(MenuOption
!= NULL
);
3137 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3138 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3141 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3142 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3150 ControlFlag
= CfCheckSelection
;
3151 if (!Selection
->FormEditable
) {
3153 // This Form is not editable, ignore the F9 (reset to default)
3158 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3160 if (!EFI_ERROR (Status
)) {
3161 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3162 Selection
->Statement
= NULL
;
3165 // Show NV update flag on status bar
3167 gNvUpdateRequired
= TRUE
;
3168 gResetRequired
= TRUE
;
3172 case CfUiNoOperation
:
3173 ControlFlag
= CfCheckSelection
;
3177 UiFreeRefreshList ();
3179 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3180 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3181 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3182 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");