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
;
346 if (gMenuRefreshHead
!= NULL
) {
348 MenuRefreshEntry
= gMenuRefreshHead
;
351 // Reset FormPackage update flag
353 mHiiPackageListUpdated
= FALSE
;
356 Selection
= MenuRefreshEntry
->Selection
;
357 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
359 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
360 if (EFI_ERROR (Status
)) {
365 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
367 if (OptionString
!= NULL
) {
369 // If leading spaces on OptionString - remove the spaces
371 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
375 // If old Text is longer than new string, need to clean the old string before paint the newer.
376 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
378 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
379 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
381 MenuRefreshEntry
->CurrentColumn
,
382 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
383 MenuRefreshEntry
->CurrentRow
,
384 MenuRefreshEntry
->CurrentRow
,
385 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
389 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
390 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
391 FreePool (OptionString
);
395 // Question value may be changed, need invoke its Callback()
397 ConfigAccess
= Selection
->FormSet
->ConfigAccess
;
398 if (((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) && (ConfigAccess
!= NULL
)) {
399 ActionRequest
= EFI_BROWSER_ACTION_REQUEST_NONE
;
400 Status
= ConfigAccess
->Callback (
402 EFI_BROWSER_ACTION_CHANGING
,
403 Question
->QuestionId
,
404 Question
->HiiValue
.Type
,
405 &Question
->HiiValue
.Value
,
408 if (!EFI_ERROR (Status
)) {
409 switch (ActionRequest
) {
410 case EFI_BROWSER_ACTION_REQUEST_RESET
:
411 gResetRequired
= TRUE
;
414 case EFI_BROWSER_ACTION_REQUEST_SUBMIT
:
415 SubmitForm (Selection
->FormSet
, Selection
->Form
);
418 case EFI_BROWSER_ACTION_REQUEST_EXIT
:
419 Selection
->Action
= UI_ACTION_EXIT
;
420 gNvUpdateRequired
= FALSE
;
429 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
431 } while (MenuRefreshEntry
!= NULL
);
433 if (mHiiPackageListUpdated
) {
435 // Package list is updated, force to reparse IFR binary of target Formset
437 mHiiPackageListUpdated
= FALSE
;
438 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
448 Wait for a given event to fire, or for an optional timeout to expire.
450 @param Event The event to wait for
451 @param Timeout An optional timeout value in 100 ns units.
452 @param RefreshInterval Menu refresh interval (in seconds).
454 @retval EFI_SUCCESS Event fired before Timeout expired.
455 @retval EFI_TIME_OUT Timout expired before Event fired.
459 UiWaitForSingleEvent (
461 IN UINT64 Timeout
, OPTIONAL
462 IN UINT8 RefreshInterval OPTIONAL
467 EFI_EVENT TimerEvent
;
468 EFI_EVENT WaitList
[2];
472 // Create a timer event
474 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
475 if (!EFI_ERROR (Status
)) {
477 // Set the timer event
486 // Wait for the original event or the timer
489 WaitList
[1] = TimerEvent
;
490 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
491 gBS
->CloseEvent (TimerEvent
);
494 // If the timer expired, change the return to timed out
496 if (!EFI_ERROR (Status
) && Index
== 1) {
497 Status
= EFI_TIMEOUT
;
502 // Update screen every second
504 if (RefreshInterval
== 0) {
505 Timeout
= ONE_SECOND
;
507 Timeout
= RefreshInterval
* ONE_SECOND
;
511 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
514 // Set the timer event
523 // Wait for the original event or the timer
526 WaitList
[1] = TimerEvent
;
527 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
530 // If the timer expired, update anything that needs a refresh and keep waiting
532 if (!EFI_ERROR (Status
) && Index
== 1) {
533 Status
= EFI_TIMEOUT
;
534 if (RefreshInterval
!= 0) {
535 Status
= RefreshForm ();
539 gBS
->CloseEvent (TimerEvent
);
540 } while (Status
== EFI_TIMEOUT
);
548 Add one menu option by specified description and context.
550 @param String String description for this option.
551 @param Handle Hii handle for the package list.
552 @param Statement Statement of this Menu Option.
553 @param NumberOfLines Display lines for this Menu Option.
554 @param MenuItemCount The index for this Option in the Menu.
556 @retval Pointer Pointer to the added Menu Option.
562 IN EFI_HII_HANDLE Handle
,
563 IN FORM_BROWSER_STATEMENT
*Statement
,
564 IN UINT16 NumberOfLines
,
565 IN UINT16 MenuItemCount
568 UI_MENU_OPTION
*MenuOption
;
575 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
577 // Add three MenuOptions for Date/Time
578 // Data format : [01/02/2004] [11:22:33]
579 // Line number : 0 0 1 0 0 1
584 if (Statement
->Storage
== NULL
) {
586 // For RTC type of date/time, set default refresh interval to be 1 second
588 if (Statement
->RefreshInterval
== 0) {
589 Statement
->RefreshInterval
= 1;
594 for (Index
= 0; Index
< Count
; Index
++) {
595 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
598 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
599 MenuOption
->Description
= String
;
600 MenuOption
->Handle
= Handle
;
601 MenuOption
->ThisTag
= Statement
;
602 MenuOption
->EntryNumber
= MenuItemCount
;
606 // Override LineNumber for the MenuOption in Date/Time sequence
608 MenuOption
->Skip
= 1;
610 MenuOption
->Skip
= NumberOfLines
;
612 MenuOption
->Sequence
= Index
;
614 if (Statement
->GrayOutExpression
!= NULL
) {
615 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
618 switch (Statement
->Operand
) {
619 case EFI_IFR_ORDERED_LIST_OP
:
620 case EFI_IFR_ONE_OF_OP
:
621 case EFI_IFR_NUMERIC_OP
:
622 case EFI_IFR_TIME_OP
:
623 case EFI_IFR_DATE_OP
:
624 case EFI_IFR_CHECKBOX_OP
:
625 case EFI_IFR_PASSWORD_OP
:
626 case EFI_IFR_STRING_OP
:
628 // User could change the value of these items
630 MenuOption
->IsQuestion
= TRUE
;
633 case EFI_IFR_TEXT_OP
:
634 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
636 // Initializing GrayOut option as TRUE for Text setup options
637 // so that those options will be Gray in colour and un selectable.
639 MenuOption
->GrayOut
= TRUE
;
643 MenuOption
->IsQuestion
= FALSE
;
647 if ((Statement
->ValueExpression
!= NULL
) ||
648 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
649 MenuOption
->ReadOnly
= TRUE
;
652 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
660 Routine used to abstract a generic dialog interface and return the selected key or string
662 @param NumberOfLines The number of lines for the dialog box
663 @param HotKey Defines whether a single character is parsed
664 (TRUE) and returned in KeyValue or a string is
665 returned in StringBuffer. Two special characters
666 are considered when entering a string, a SCAN_ESC
667 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
668 string input and returns
669 @param MaximumStringSize The maximum size in bytes of a typed in string
670 (each character is a CHAR16) and the minimum
671 string returned is two bytes
672 @param StringBuffer The passed in pointer to the buffer which will
673 hold the typed in string if HotKey is FALSE
674 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
675 @param ... A series of (quantity == NumberOfLines) text
676 strings which will be used to construct the dialog
679 @retval EFI_SUCCESS Displayed dialog and received user interaction
680 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
681 (StringBuffer == NULL) && (HotKey == FALSE))
682 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
688 IN UINTN NumberOfLines
,
690 IN UINTN MaximumStringSize
,
691 OUT CHAR16
*StringBuffer
,
692 OUT EFI_INPUT_KEY
*KeyValue
,
701 CHAR16
*BufferedString
;
708 BOOLEAN SelectionComplete
;
710 UINTN CurrentAttribute
;
711 UINTN DimensionsWidth
;
712 UINTN DimensionsHeight
;
714 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
715 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
717 SelectionComplete
= FALSE
;
719 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
720 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
721 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
724 ASSERT (BufferedString
);
726 VA_START (Marker
, KeyValue
);
729 // Zero the outgoing buffer
731 ZeroMem (StringBuffer
, MaximumStringSize
);
734 if (KeyValue
== NULL
) {
735 return EFI_INVALID_PARAMETER
;
738 if (StringBuffer
== NULL
) {
739 return EFI_INVALID_PARAMETER
;
745 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
750 // Determine the largest string in the dialog box
751 // Notice we are starting with 1 since String is the first string
753 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
754 StackString
= VA_ARG (Marker
, CHAR16
*);
756 if (StackString
[0] == L
' ') {
757 InputOffset
= Count
+ 1;
760 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
762 // Size of the string visually and subtract the width by one for the null-terminator
764 LargestString
= (GetStringWidth (StackString
) / 2);
769 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
770 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
777 VA_START (Marker
, KeyValue
);
778 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
782 // Take the first key typed and report it back?
785 Status
= WaitForKeyStroke (&Key
);
786 ASSERT_EFI_ERROR (Status
);
787 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
791 Status
= WaitForKeyStroke (&Key
);
793 switch (Key
.UnicodeChar
) {
795 switch (Key
.ScanCode
) {
797 FreePool (TempString
);
798 FreePool (BufferedString
);
799 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
800 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
801 return EFI_DEVICE_ERROR
;
809 case CHAR_CARRIAGE_RETURN
:
810 SelectionComplete
= TRUE
;
811 FreePool (TempString
);
812 FreePool (BufferedString
);
813 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
814 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
819 if (StringBuffer
[0] != CHAR_NULL
) {
820 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
821 TempString
[Index
] = StringBuffer
[Index
];
824 // Effectively truncate string by 1 character
826 TempString
[Index
- 1] = CHAR_NULL
;
827 StrCpy (StringBuffer
, TempString
);
832 // If it is the beginning of the string, don't worry about checking maximum limits
834 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
835 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
836 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
837 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
838 KeyPad
[0] = Key
.UnicodeChar
;
839 KeyPad
[1] = CHAR_NULL
;
840 StrCat (StringBuffer
, KeyPad
);
841 StrCat (TempString
, KeyPad
);
844 // If the width of the input string is now larger than the screen, we nee to
845 // adjust the index to start printing portions of the string
847 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
849 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
851 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
852 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
857 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
858 BufferedString
[Count
] = StringBuffer
[Index
];
861 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
864 } while (!SelectionComplete
);
867 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
868 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
873 Draw a pop up windows based on the dimension, number of lines and
876 @param RequestedWidth The width of the pop-up.
877 @param NumberOfLines The number of lines.
878 @param Marker The variable argument list for the list of string to be printed.
883 IN UINTN RequestedWidth
,
884 IN UINTN NumberOfLines
,
896 UINTN DimensionsWidth
;
897 UINTN DimensionsHeight
;
899 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
900 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
902 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
904 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
905 RequestedWidth
= DimensionsWidth
- 2;
909 // Subtract the PopUp width from total Columns, allow for one space extra on
910 // each end plus a border.
912 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
913 End
= Start
+ RequestedWidth
+ 1;
915 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
916 Bottom
= Top
+ NumberOfLines
+ 2;
918 Character
= BOXDRAW_DOWN_RIGHT
;
919 PrintCharAt (Start
, Top
, Character
);
920 Character
= BOXDRAW_HORIZONTAL
;
921 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
922 PrintChar (Character
);
925 Character
= BOXDRAW_DOWN_LEFT
;
926 PrintChar (Character
);
927 Character
= BOXDRAW_VERTICAL
;
930 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
931 String
= VA_ARG (Marker
, CHAR16
*);
934 // This will clear the background of the line - we never know who might have been
935 // here before us. This differs from the next clear in that it used the non-reverse
936 // video for normal printing.
938 if (GetStringWidth (String
) / 2 > 1) {
939 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
943 // Passing in a space results in the assumption that this is where typing will occur
945 if (String
[0] == L
' ') {
946 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
950 // Passing in a NULL results in a blank space
952 if (String
[0] == CHAR_NULL
) {
953 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
957 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
961 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
962 PrintCharAt (Start
, Index
+ 1, Character
);
963 PrintCharAt (End
- 1, Index
+ 1, Character
);
966 Character
= BOXDRAW_UP_RIGHT
;
967 PrintCharAt (Start
, Bottom
- 1, Character
);
968 Character
= BOXDRAW_HORIZONTAL
;
969 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
970 PrintChar (Character
);
973 Character
= BOXDRAW_UP_LEFT
;
974 PrintChar (Character
);
978 Draw a pop up windows based on the dimension, number of lines and
981 @param RequestedWidth The width of the pop-up.
982 @param NumberOfLines The number of lines.
983 @param ... A series of text strings that displayed in the pop-up.
988 CreateMultiStringPopUp (
989 IN UINTN RequestedWidth
,
990 IN UINTN NumberOfLines
,
996 VA_START (Marker
, NumberOfLines
);
998 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1005 Update status bar on the bottom of menu.
1007 @param MessageType The type of message to be shown.
1008 @param Flags The flags in Question header.
1009 @param State Set or clear.
1014 IN UINTN MessageType
,
1020 CHAR16
*NvUpdateMessage
;
1021 CHAR16
*InputErrorMessage
;
1023 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1024 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1026 switch (MessageType
) {
1029 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1031 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1032 gScreenDimensions
.BottomRow
- 1,
1037 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1038 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1039 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1042 mInputError
= FALSE
;
1046 case NV_UPDATE_REQUIRED
:
1047 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
1049 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1051 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1052 gScreenDimensions
.BottomRow
- 1,
1055 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1057 gNvUpdateRequired
= TRUE
;
1059 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1060 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1062 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1063 gScreenDimensions
.BottomRow
- 1,
1068 gNvUpdateRequired
= FALSE
;
1073 case REFRESH_STATUS_BAR
:
1075 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
1078 if (gNvUpdateRequired
) {
1079 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1087 FreePool (InputErrorMessage
);
1088 FreePool (NvUpdateMessage
);
1094 Get the supported width for a particular op-code
1096 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1097 @param Handle The handle in the HII database being used
1099 @return Returns the number of CHAR16 characters that is support.
1104 IN FORM_BROWSER_STATEMENT
*Statement
,
1105 IN EFI_HII_HANDLE Handle
1115 // See if the second text parameter is really NULL
1117 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1118 String
= GetToken (Statement
->TextTwo
, Handle
);
1119 Size
= StrLen (String
);
1123 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1124 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1125 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1126 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1127 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1129 // Allow a wide display if text op-code and no secondary text op-code
1131 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1133 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1135 Width
= (UINT16
) gPromptBlockWidth
;
1138 if (Statement
->InSubtitle
) {
1139 Width
-= SUBTITLE_INDENT
;
1142 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1146 Will copy LineWidth amount of a string in the OutputString buffer and return the
1147 number of CHAR16 characters that were copied into the OutputString buffer.
1149 @param InputString String description for this option.
1150 @param LineWidth Width of the desired string to extract in CHAR16
1152 @param Index Where in InputString to start the copy process
1153 @param OutputString Buffer to copy the string into
1155 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1160 IN CHAR16
*InputString
,
1161 IN UINT16 LineWidth
,
1162 IN OUT UINTN
*Index
,
1163 OUT CHAR16
**OutputString
1169 if (GetLineByWidthFinished
) {
1170 GetLineByWidthFinished
= FALSE
;
1177 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1180 // Ensure we have got a valid buffer
1182 if (*OutputString
!= NULL
) {
1185 //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.
1186 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1188 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1189 *Index
= *Index
+ 2;
1193 // Fast-forward the string and see if there is a carriage-return in the string
1195 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1199 // Copy the desired LineWidth of data to the output buffer.
1200 // Also make sure that we don't copy more than the string.
1201 // Also make sure that if there are linefeeds, we account for them.
1203 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1204 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1207 // Convert to CHAR16 value and show that we are done with this operation
1209 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1210 if (LineWidth
!= 0) {
1211 GetLineByWidthFinished
= TRUE
;
1214 if (Count2
== LineWidth
) {
1216 // Rewind the string from the maximum size until we see a space to break the line
1218 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1220 if (LineWidth
== 0) {
1228 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1231 // If currently pointing to a space, increment the index to the first non-space character
1234 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1238 *Index
= (UINT16
) (*Index
+ LineWidth
);
1247 Update display lines for a Menu Option.
1249 @param Selection The user's selection.
1250 @param MenuOption The MenuOption to be checked.
1251 @param OptionalString The option string.
1252 @param SkipValue The number of lins to skip.
1256 UpdateOptionSkipLines (
1257 IN UI_MENU_SELECTION
*Selection
,
1258 IN UI_MENU_OPTION
*MenuOption
,
1259 OUT CHAR16
**OptionalString
,
1267 CHAR16
*OutputString
;
1268 CHAR16
*OptionString
;
1271 OptionString
= *OptionalString
;
1272 OutputString
= NULL
;
1274 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1276 if (OptionString
!= NULL
) {
1277 Width
= (UINT16
) gOptionBlockWidth
;
1281 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1283 // If there is more string to process print on the next row and increment the Skip value
1285 if (StrLen (&OptionString
[Index
]) != 0) {
1286 if (SkipValue
== 0) {
1289 // Since the Number of lines for this menu entry may or may not be reflected accurately
1290 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1291 // some testing to ensure we are keeping this in-sync.
1293 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1295 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1301 FreePool (OutputString
);
1302 if (SkipValue
!= 0) {
1310 *OptionalString
= OptionString
;
1315 Check whether this Menu Option could be highlighted.
1317 This is an internal function.
1319 @param MenuOption The MenuOption to be checked.
1321 @retval TRUE This Menu Option is selectable.
1322 @retval FALSE This Menu Option could not be selected.
1327 UI_MENU_OPTION
*MenuOption
1330 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1331 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1340 Determine if the menu is the last menu that can be selected.
1342 This is an internal function.
1344 @param Direction The scroll direction. False is down. True is up.
1345 @param CurrentPos The current focus.
1347 @return FALSE -- the menu isn't the last menu that can be selected.
1348 @return TRUE -- the menu is the last menu that can be selected.
1353 IN BOOLEAN Direction
,
1354 IN LIST_ENTRY
*CurrentPos
1359 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1361 if (Temp
== &gMenuOption
) {
1370 Move to next selectable statement.
1372 This is an internal function.
1374 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1375 @param CurrentPosition Current position.
1376 @param GapToTop Gap position to top or bottom.
1378 @return The row distance from current MenuOption to next selectable MenuOption.
1382 MoveToNextStatement (
1384 IN OUT LIST_ENTRY
**CurrentPosition
,
1390 UI_MENU_OPTION
*NextMenuOption
;
1391 UI_MENU_OPTION
*PreMenuOption
;
1394 Pos
= *CurrentPosition
;
1395 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1398 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1399 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1401 // Current Position doesn't need to be caculated when go up.
1402 // Caculate distanct at first when go up
1404 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1405 NextMenuOption
= PreMenuOption
;
1408 Distance
+= NextMenuOption
->Skip
;
1410 if (IsSelectable (NextMenuOption
)) {
1413 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1422 // Caculate distanct at later when go down
1424 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1425 NextMenuOption
= PreMenuOption
;
1428 Distance
+= NextMenuOption
->Skip
;
1430 PreMenuOption
= NextMenuOption
;
1431 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1434 *CurrentPosition
= &NextMenuOption
->Link
;
1440 Adjust Data and Time position accordingly.
1441 Data format : [01/02/2004] [11:22:33]
1442 Line number : 0 0 1 0 0 1
1444 This is an internal function.
1446 @param DirectionUp the up or down direction. False is down. True is
1448 @param CurrentPosition Current position. On return: Point to the last
1449 Option (Year or Second) if up; Point to the first
1450 Option (Month or Hour) if down.
1452 @return Return line number to pad. It is possible that we stand on a zero-advance
1453 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1457 AdjustDateAndTimePosition (
1458 IN BOOLEAN DirectionUp
,
1459 IN OUT LIST_ENTRY
**CurrentPosition
1463 LIST_ENTRY
*NewPosition
;
1464 UI_MENU_OPTION
*MenuOption
;
1465 UINTN PadLineNumber
;
1468 NewPosition
= *CurrentPosition
;
1469 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1471 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1472 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1474 // Calculate the distance from current position to the last Date/Time MenuOption
1477 while (MenuOption
->Skip
== 0) {
1479 NewPosition
= NewPosition
->ForwardLink
;
1480 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1484 NewPosition
= *CurrentPosition
;
1487 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1488 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1489 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1490 // checking can be done.
1492 while (Count
++ < 2) {
1493 NewPosition
= NewPosition
->BackLink
;
1497 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1498 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1499 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1500 // checking can be done.
1502 while (Count
-- > 0) {
1503 NewPosition
= NewPosition
->ForwardLink
;
1507 *CurrentPosition
= NewPosition
;
1510 return PadLineNumber
;
1514 Find HII Handle in the HII database associated with given Device Path.
1516 If DevicePath is NULL, then ASSERT.
1518 @param DevicePath Device Path associated with the HII package list
1521 @retval Handle HII package list Handle associated with the Device
1523 @retval NULL Hii Package list handle is not found.
1528 DevicePathToHiiHandle (
1529 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1533 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1538 EFI_HANDLE DriverHandle
;
1539 EFI_HII_HANDLE
*HiiHandles
;
1540 EFI_HII_HANDLE HiiHandle
;
1542 ASSERT (DevicePath
!= NULL
);
1544 TmpDevicePath
= DevicePath
;
1546 // Locate Device Path Protocol handle buffer
1548 Status
= gBS
->LocateDevicePath (
1549 &gEfiDevicePathProtocolGuid
,
1553 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1558 // Retrieve all HII Handles from HII database
1560 BufferSize
= 0x1000;
1561 HiiHandles
= AllocatePool (BufferSize
);
1562 ASSERT (HiiHandles
!= NULL
);
1563 Status
= mHiiDatabase
->ListPackageLists (
1565 EFI_HII_PACKAGE_TYPE_ALL
,
1570 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1571 FreePool (HiiHandles
);
1572 HiiHandles
= AllocatePool (BufferSize
);
1573 ASSERT (HiiHandles
!= NULL
);
1575 Status
= mHiiDatabase
->ListPackageLists (
1577 EFI_HII_PACKAGE_TYPE_ALL
,
1584 if (EFI_ERROR (Status
)) {
1585 FreePool (HiiHandles
);
1590 // Search Hii Handle by Driver Handle
1593 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1594 for (Index
= 0; Index
< HandleCount
; Index
++) {
1595 Status
= mHiiDatabase
->GetPackageListHandle (
1600 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1601 HiiHandle
= HiiHandles
[Index
];
1606 FreePool (HiiHandles
);
1611 Display menu and wait for user to select one menu option, then return it.
1612 If AutoBoot is enabled, then if user doesn't select any option,
1613 after period of time, it will automatically return the first menu option.
1615 @param Selection Menu selection.
1617 @retval EFI_SUCESSS This function always return successfully for now.
1622 IN OUT UI_MENU_SELECTION
*Selection
1628 UINTN DistanceValue
;
1640 CHAR16
*OptionString
;
1641 CHAR16
*OutputString
;
1642 CHAR16
*FormattedString
;
1650 BOOLEAN InitializedFlag
;
1655 LIST_ENTRY
*TopOfScreen
;
1656 LIST_ENTRY
*SavedListEntry
;
1657 UI_MENU_OPTION
*MenuOption
;
1658 UI_MENU_OPTION
*NextMenuOption
;
1659 UI_MENU_OPTION
*SavedMenuOption
;
1660 UI_MENU_OPTION
*PreviousMenuOption
;
1661 UI_CONTROL_FLAG ControlFlag
;
1662 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1663 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1664 UI_SCREEN_OPERATION ScreenOperation
;
1665 UINT8 MinRefreshInterval
;
1668 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1669 FORM_BROWSER_STATEMENT
*Statement
;
1671 UINT8
*DevicePathBuffer
;
1673 UI_MENU_LIST
*CurrentMenu
;
1674 UI_MENU_LIST
*MenuList
;
1675 FORM_BROWSER_FORM
*RefForm
;
1677 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1679 Status
= EFI_SUCCESS
;
1680 FormattedString
= NULL
;
1681 OptionString
= NULL
;
1682 ScreenOperation
= UiNoOperation
;
1684 MinRefreshInterval
= 0;
1687 OutputString
= NULL
;
1692 MenuRefreshEntry
= gMenuRefreshHead
;
1694 NextMenuOption
= NULL
;
1695 PreviousMenuOption
= NULL
;
1696 SavedMenuOption
= NULL
;
1699 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1701 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1702 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1703 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1705 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1706 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1709 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1710 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1712 Selection
->TopRow
= TopRow
;
1713 Selection
->BottomRow
= BottomRow
;
1714 Selection
->PromptCol
= Col
;
1715 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1716 Selection
->Statement
= NULL
;
1718 TopOfScreen
= gMenuOption
.ForwardLink
;
1723 // Find current Menu
1725 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1726 if (CurrentMenu
== NULL
) {
1728 // Current menu not found, add it to the menu tree
1730 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1732 ASSERT (CurrentMenu
!= NULL
);
1734 if (Selection
->QuestionId
== 0) {
1736 // Highlight not specified, fetch it from cached menu
1738 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1742 // Init option as the current user's selection
1744 InitializedFlag
= TRUE
;
1745 NewPos
= gMenuOption
.ForwardLink
;
1747 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1748 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1750 ControlFlag
= CfInitialization
;
1751 Selection
->Action
= UI_ACTION_NONE
;
1753 switch (ControlFlag
) {
1754 case CfInitialization
:
1755 if (IsListEmpty (&gMenuOption
)) {
1756 ControlFlag
= CfReadKey
;
1758 ControlFlag
= CfCheckSelection
;
1762 case CfCheckSelection
:
1763 if (Selection
->Action
!= UI_ACTION_NONE
) {
1764 ControlFlag
= CfExit
;
1766 ControlFlag
= CfRepaint
;
1771 ControlFlag
= CfRefreshHighLight
;
1781 Temp
= (UINTN
) SkipValue
;
1782 Temp2
= (UINTN
) SkipValue
;
1785 LocalScreen
.LeftColumn
,
1786 LocalScreen
.RightColumn
,
1787 TopRow
- SCROLL_ARROW_HEIGHT
,
1788 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1789 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1792 UiFreeRefreshList ();
1793 MinRefreshInterval
= 0;
1795 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1796 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1797 MenuOption
->Row
= Row
;
1798 MenuOption
->Col
= Col
;
1799 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1801 Statement
= MenuOption
->ThisTag
;
1802 if (Statement
->InSubtitle
) {
1803 MenuOption
->Col
+= SUBTITLE_INDENT
;
1806 if (MenuOption
->GrayOut
) {
1807 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1809 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1810 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
1814 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1817 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1819 // Print Arrow for Goto button.
1822 MenuOption
->Col
- 2,
1825 GEOMETRICSHAPE_RIGHT_TRIANGLE
1829 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1830 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1831 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1834 // If there is more string to process print on the next row and increment the Skip value
1836 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1842 FreePool (OutputString
);
1851 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1852 if (EFI_ERROR (Status
)) {
1854 // Repaint to clear possible error prompt pop-up
1858 ControlFlag
= CfRepaint
;
1862 if (OptionString
!= NULL
) {
1863 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1865 // If leading spaces on OptionString - remove the spaces
1867 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1868 MenuOption
->OptCol
++;
1871 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1872 OptionString
[Count
] = OptionString
[Index
];
1876 OptionString
[Count
] = CHAR_NULL
;
1880 // If Question request refresh, register the op-code
1882 if (Statement
->RefreshInterval
!= 0) {
1884 // Menu will be refreshed at minimal interval of all Questions
1885 // which have refresh request
1887 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1888 MinRefreshInterval
= Statement
->RefreshInterval
;
1891 if (gMenuRefreshHead
== NULL
) {
1892 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1893 ASSERT (MenuRefreshEntry
!= NULL
);
1894 MenuRefreshEntry
->MenuOption
= MenuOption
;
1895 MenuRefreshEntry
->Selection
= Selection
;
1896 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1897 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1898 if (MenuOption
->GrayOut
) {
1899 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1901 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1903 gMenuRefreshHead
= MenuRefreshEntry
;
1906 // Advance to the last entry
1908 for (MenuRefreshEntry
= gMenuRefreshHead
;
1909 MenuRefreshEntry
->Next
!= NULL
;
1910 MenuRefreshEntry
= MenuRefreshEntry
->Next
1913 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1914 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1915 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1916 MenuRefreshEntry
->MenuOption
= MenuOption
;
1917 MenuRefreshEntry
->Selection
= Selection
;
1918 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1919 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1920 if (MenuOption
->GrayOut
) {
1921 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1923 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1928 Width
= (UINT16
) gOptionBlockWidth
;
1931 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1932 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1933 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1936 // If there is more string to process print on the next row and increment the Skip value
1938 if (StrLen (&OptionString
[Index
]) != 0) {
1942 // Since the Number of lines for this menu entry may or may not be reflected accurately
1943 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1944 // some testing to ensure we are keeping this in-sync.
1946 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1948 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1954 FreePool (OutputString
);
1963 FreePool (OptionString
);
1966 // If this is a text op with secondary text information
1968 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1969 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
1971 Width
= (UINT16
) gOptionBlockWidth
;
1974 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1975 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1976 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1979 // If there is more string to process print on the next row and increment the Skip value
1981 if (StrLen (&StringPtr
[Index
]) != 0) {
1985 // Since the Number of lines for this menu entry may or may not be reflected accurately
1986 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1987 // some testing to ensure we are keeping this in-sync.
1989 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1991 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1997 FreePool (OutputString
);
2004 FreePool (StringPtr
);
2006 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2009 // Need to handle the bottom of the display
2011 if (MenuOption
->Skip
> 1) {
2012 Row
+= MenuOption
->Skip
- SkipValue
;
2015 Row
+= MenuOption
->Skip
;
2018 if (Row
> BottomRow
) {
2019 if (!ValueIsScroll (FALSE
, Link
)) {
2023 Row
= BottomRow
+ 1;
2028 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2033 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2035 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2036 TopRow
- SCROLL_ARROW_HEIGHT
,
2040 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2044 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2046 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2047 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2051 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2058 case CfRefreshHighLight
:
2060 // MenuOption: Last menu option that need to remove hilight
2061 // MenuOption is set to NULL in Repaint
2062 // NewPos: Current menu option that need to hilight
2064 ControlFlag
= CfUpdateHelpString
;
2065 if (InitializedFlag
) {
2066 InitializedFlag
= FALSE
;
2067 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2071 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2072 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2074 SavedValue
= Repaint
;
2077 if (Selection
->QuestionId
!= 0) {
2078 NewPos
= gMenuOption
.ForwardLink
;
2079 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2081 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &gMenuOption
) {
2082 NewPos
= NewPos
->ForwardLink
;
2083 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2085 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2087 // Target Question found, find its MenuOption
2091 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2092 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2093 Index
+= SavedMenuOption
->Skip
;
2094 Link
= Link
->ForwardLink
;
2097 if (Link
!= NewPos
|| Index
> BottomRow
) {
2099 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2102 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2103 Link
= Link
->BackLink
;
2104 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2105 Index
+= SavedMenuOption
->Skip
;
2107 TopOfScreen
= Link
->ForwardLink
;
2111 ControlFlag
= CfRepaint
;
2116 // Target Question not found, highlight the default menu option
2118 NewPos
= TopOfScreen
;
2121 Selection
->QuestionId
= 0;
2124 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2125 if (MenuOption
!= NULL
) {
2127 // Remove highlight on last Menu Option
2129 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2130 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2131 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2132 if (OptionString
!= NULL
) {
2133 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2134 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2137 // If leading spaces on OptionString - remove the spaces
2139 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2142 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2143 OptionString
[Count
] = OptionString
[Index
];
2147 OptionString
[Count
] = CHAR_NULL
;
2150 Width
= (UINT16
) gOptionBlockWidth
;
2151 OriginalRow
= MenuOption
->Row
;
2153 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2154 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2155 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2158 // If there is more string to process print on the next row and increment the Skip value
2160 if (StrLen (&OptionString
[Index
]) != 0) {
2164 FreePool (OutputString
);
2167 MenuOption
->Row
= OriginalRow
;
2169 FreePool (OptionString
);
2172 if (MenuOption
->GrayOut
) {
2173 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2174 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2175 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2178 OriginalRow
= MenuOption
->Row
;
2179 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2181 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2182 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2183 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2186 // If there is more string to process print on the next row and increment the Skip value
2188 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2192 FreePool (OutputString
);
2195 MenuOption
->Row
= OriginalRow
;
2196 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2202 // This is the current selected statement
2204 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2205 Statement
= MenuOption
->ThisTag
;
2206 Selection
->Statement
= Statement
;
2207 if (!IsSelectable (MenuOption
)) {
2208 Repaint
= SavedValue
;
2209 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2214 // Record highlight for current menu
2216 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2219 // Set reverse attribute
2221 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2222 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2225 // Assuming that we have a refresh linked-list created, lets annotate the
2226 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2227 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2229 if (gMenuRefreshHead
!= NULL
) {
2230 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2231 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2232 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2234 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2236 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2237 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2242 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2243 if (OptionString
!= NULL
) {
2244 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2246 // If leading spaces on OptionString - remove the spaces
2248 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2251 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2252 OptionString
[Count
] = OptionString
[Index
];
2256 OptionString
[Count
] = CHAR_NULL
;
2258 Width
= (UINT16
) gOptionBlockWidth
;
2260 OriginalRow
= MenuOption
->Row
;
2262 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2263 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2264 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2267 // If there is more string to process print on the next row and increment the Skip value
2269 if (StrLen (&OptionString
[Index
]) != 0) {
2273 FreePool (OutputString
);
2276 MenuOption
->Row
= OriginalRow
;
2278 FreePool (OptionString
);
2281 OriginalRow
= MenuOption
->Row
;
2283 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2285 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2286 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2287 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2290 // If there is more string to process print on the next row and increment the Skip value
2292 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2296 FreePool (OutputString
);
2299 MenuOption
->Row
= OriginalRow
;
2304 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2307 // Clear reverse attribute
2309 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2312 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2313 // if we didn't break halfway when process CfRefreshHighLight.
2315 Repaint
= SavedValue
;
2318 case CfUpdateHelpString
:
2319 ControlFlag
= CfPrepareToReadKey
;
2321 if (Repaint
|| NewLine
) {
2323 // Don't print anything if it is a NULL help token
2325 ASSERT(MenuOption
!= NULL
);
2326 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2329 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2332 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2334 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2336 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2338 // Pad String with spaces to simulate a clearing of the previous line
2340 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2341 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2345 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2347 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2352 // Reset this flag every time we finish using it.
2358 case CfPrepareToReadKey
:
2359 ControlFlag
= CfReadKey
;
2360 ScreenOperation
= UiNoOperation
;
2364 ControlFlag
= CfScreenOperation
;
2367 // Wait for user's selection
2370 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2371 } while (Status
== EFI_TIMEOUT
);
2373 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2375 // IFR is updated in Callback of refresh opcode, re-parse it
2377 Selection
->Statement
= NULL
;
2381 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2383 // If we encounter error, continue to read another key in.
2385 if (EFI_ERROR (Status
)) {
2386 ControlFlag
= CfReadKey
;
2390 switch (Key
.UnicodeChar
) {
2391 case CHAR_CARRIAGE_RETURN
:
2392 ScreenOperation
= UiSelect
;
2397 // We will push the adjustment of these numeric values directly to the input handler
2398 // NOTE: we won't handle manual input numeric
2403 // If the screen has no menu items, and the user didn't select UiReset
2404 // ignore the selection and go back to reading keys.
2406 if(IsListEmpty (&gMenuOption
)) {
2407 ControlFlag
= CfReadKey
;
2411 ASSERT(MenuOption
!= NULL
);
2412 Statement
= MenuOption
->ThisTag
;
2413 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2414 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2415 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2417 if (Key
.UnicodeChar
== '+') {
2418 gDirection
= SCAN_RIGHT
;
2420 gDirection
= SCAN_LEFT
;
2422 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2423 if (EFI_ERROR (Status
)) {
2425 // Repaint to clear possible error prompt pop-up
2430 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2432 if (OptionString
!= NULL
) {
2433 FreePool (OptionString
);
2439 ScreenOperation
= UiUp
;
2444 ScreenOperation
= UiDown
;
2448 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2450 // If the screen has no menu items, and the user didn't select UiReset
2451 // ignore the selection and go back to reading keys.
2453 if(IsListEmpty (&gMenuOption
)) {
2454 ControlFlag
= CfReadKey
;
2458 ASSERT(MenuOption
!= NULL
);
2459 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2460 ScreenOperation
= UiSelect
;
2466 if (((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2467 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2470 // If the function key has been disabled, just ignore the key.
2473 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2474 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2475 if (Key
.ScanCode
== SCAN_F9
) {
2477 // Reset to standard default
2479 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2481 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2490 case CfScreenOperation
:
2491 if (ScreenOperation
!= UiReset
) {
2493 // If the screen has no menu items, and the user didn't select UiReset
2494 // ignore the selection and go back to reading keys.
2496 if (IsListEmpty (&gMenuOption
)) {
2497 ControlFlag
= CfReadKey
;
2503 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2506 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2507 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2514 ControlFlag
= CfCheckSelection
;
2516 ASSERT(MenuOption
!= NULL
);
2517 Statement
= MenuOption
->ThisTag
;
2518 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2523 // Keep highlight on current MenuOption
2525 Selection
->QuestionId
= Statement
->QuestionId
;
2527 switch (Statement
->Operand
) {
2528 case EFI_IFR_REF_OP
:
2529 if (Statement
->RefDevicePath
!= 0) {
2531 // Goto another Hii Package list
2533 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2535 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2536 if (StringPtr
== NULL
) {
2538 // No device path string not found, exit
2540 Selection
->Action
= UI_ACTION_EXIT
;
2541 Selection
->Statement
= NULL
;
2544 BufferSize
= StrLen (StringPtr
) / 2;
2545 DevicePath
= AllocatePool (BufferSize
);
2546 ASSERT (DevicePath
!= NULL
);
2549 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2551 DevicePathBuffer
= (UINT8
*) DevicePath
;
2552 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2553 TemStr
[0] = StringPtr
[Index
];
2554 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2555 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2557 // Invalid Hex Char as the tail.
2561 if ((Index
& 1) == 0) {
2562 DevicePathBuffer
[Index
/2] = DigitUint8
;
2564 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2568 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2569 if (Selection
->Handle
== NULL
) {
2571 // If target Hii Handle not found, exit
2573 Selection
->Action
= UI_ACTION_EXIT
;
2574 Selection
->Statement
= NULL
;
2578 FreePool (StringPtr
);
2579 FreePool (DevicePath
);
2581 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2582 Selection
->FormId
= Statement
->RefFormId
;
2583 Selection
->QuestionId
= Statement
->RefQuestionId
;
2584 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2586 // Goto another Formset, check for uncommitted data
2588 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2590 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2591 Selection
->FormId
= Statement
->RefFormId
;
2592 Selection
->QuestionId
= Statement
->RefQuestionId
;
2593 } else if (Statement
->RefFormId
!= 0) {
2595 // Check whether target From is suppressed.
2597 RefForm
= IdToForm (Selection
->FormSet
, Statement
->RefFormId
);
2599 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2600 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
2601 if (EFI_ERROR (Status
)) {
2605 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
2607 // Form is suppressed.
2610 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2611 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2619 // Goto another form inside this formset,
2621 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2624 // Link current form so that we can always go back when someone hits the ESC
2626 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->RefFormId
);
2627 if (MenuList
== NULL
) {
2628 MenuList
= UiAddMenuList (CurrentMenu
, &Selection
->FormSetGuid
, Statement
->RefFormId
);
2631 Selection
->FormId
= Statement
->RefFormId
;
2632 Selection
->QuestionId
= Statement
->RefQuestionId
;
2633 } else if (Statement
->RefQuestionId
!= 0) {
2635 // Goto another Question
2637 Selection
->QuestionId
= Statement
->RefQuestionId
;
2639 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2640 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2649 case EFI_IFR_ACTION_OP
:
2651 // Process the Config string <ConfigResp>
2653 Status
= ProcessQuestionConfig (Selection
, Statement
);
2655 if (EFI_ERROR (Status
)) {
2660 // The action button may change some Question value, so refresh the form
2662 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2665 case EFI_IFR_RESET_BUTTON_OP
:
2667 // Reset Question to default value specified by DefaultId
2669 ControlFlag
= CfUiDefault
;
2670 DefaultId
= Statement
->DefaultId
;
2675 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2677 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2678 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2680 if (EFI_ERROR (Status
)) {
2683 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2685 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2688 if (OptionString
!= NULL
) {
2689 FreePool (OptionString
);
2697 // We come here when someone press ESC
2699 ControlFlag
= CfCheckSelection
;
2701 if (CurrentMenu
->Parent
!= NULL
) {
2703 // we have a parent, so go to the parent menu
2705 if (CompareGuid (&CurrentMenu
->FormSetGuid
, &CurrentMenu
->Parent
->FormSetGuid
)) {
2707 // The parent menu and current menu are in the same formset
2709 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2711 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2713 Selection
->Statement
= NULL
;
2715 Selection
->FormId
= CurrentMenu
->Parent
->FormId
;
2716 Selection
->QuestionId
= CurrentMenu
->Parent
->QuestionId
;
2719 // Clear highlight record for this menu
2721 CurrentMenu
->QuestionId
= 0;
2725 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
) {
2727 // We never exit FrontPage, so skip the ESC
2729 Selection
->Action
= UI_ACTION_NONE
;
2734 // We are going to leave current FormSet, so check uncommited data in this FormSet
2736 if (gNvUpdateRequired
) {
2737 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2739 YesResponse
= gYesResponse
[0];
2740 NoResponse
= gNoResponse
[0];
2743 // If NV flag is up, prompt user
2746 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveChanges
, gAreYouSure
, gEmptyString
);
2749 (Key
.ScanCode
!= SCAN_ESC
) &&
2750 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2751 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2754 if (Key
.ScanCode
== SCAN_ESC
) {
2756 // User hits the ESC key
2761 Selection
->Action
= UI_ACTION_NONE
;
2766 // If the user hits the YesResponse key
2768 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2769 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
);
2773 Selection
->Action
= UI_ACTION_EXIT
;
2774 Selection
->Statement
= NULL
;
2775 CurrentMenu
->QuestionId
= 0;
2780 ControlFlag
= CfCheckSelection
;
2781 ASSERT(MenuOption
!= NULL
);
2782 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2783 if (MenuOption
->Sequence
!= 0) {
2785 // In the middle or tail of the Date/Time op-code set, go left.
2787 ASSERT(NewPos
!= NULL
);
2788 NewPos
= NewPos
->BackLink
;
2794 ControlFlag
= CfCheckSelection
;
2795 ASSERT(MenuOption
!= NULL
);
2796 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2797 if (MenuOption
->Sequence
!= 2) {
2799 // In the middle or tail of the Date/Time op-code set, go left.
2801 ASSERT(NewPos
!= NULL
);
2802 NewPos
= NewPos
->ForwardLink
;
2808 ControlFlag
= CfCheckSelection
;
2810 SavedListEntry
= NewPos
;
2812 ASSERT(NewPos
!= NULL
);
2814 // Adjust Date/Time position before we advance forward.
2816 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2817 if (NewPos
->BackLink
!= &gMenuOption
) {
2818 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2820 NewPos
= NewPos
->BackLink
;
2822 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2823 DistanceValue
= PreviousMenuOption
->Skip
;
2825 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2826 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2828 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2830 ASSERT (MenuOption
!= NULL
);
2831 if (Difference
< 0) {
2833 // We hit the begining MenuOption that can be focused
2834 // so we simply scroll to the top.
2836 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2837 TopOfScreen
= gMenuOption
.ForwardLink
;
2841 // Scroll up to the last page when we have arrived at top page.
2843 NewPos
= &gMenuOption
;
2844 TopOfScreen
= &gMenuOption
;
2845 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2846 ScreenOperation
= UiPageUp
;
2847 ControlFlag
= CfScreenOperation
;
2850 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2852 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2854 TopOfScreen
= NewPos
;
2858 } else if (!IsSelectable (NextMenuOption
)) {
2860 // Continue to go up until scroll to next page or the selectable option is found.
2862 ScreenOperation
= UiUp
;
2863 ControlFlag
= CfScreenOperation
;
2867 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2869 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2870 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2871 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2872 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2875 // Scroll up to the last page.
2877 NewPos
= &gMenuOption
;
2878 TopOfScreen
= &gMenuOption
;
2879 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2880 ScreenOperation
= UiPageUp
;
2881 ControlFlag
= CfScreenOperation
;
2886 ControlFlag
= CfCheckSelection
;
2888 ASSERT(NewPos
!= NULL
);
2889 if (NewPos
->BackLink
== &gMenuOption
) {
2899 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2900 Link
= Link
->BackLink
;
2901 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2902 if (Index
< PreviousMenuOption
->Skip
) {
2906 Index
= Index
- PreviousMenuOption
->Skip
;
2909 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2910 if (TopOfScreen
== &gMenuOption
) {
2911 TopOfScreen
= gMenuOption
.ForwardLink
;
2912 NewPos
= gMenuOption
.BackLink
;
2913 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2915 } else if (TopOfScreen
!= Link
) {
2918 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2921 // Finally we know that NewPos is the last MenuOption can be focused.
2925 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2928 if (Index
+ 1 < TopRow
) {
2930 // Back up the previous option.
2932 Link
= Link
->ForwardLink
;
2936 // Move to the option in Next page.
2938 if (TopOfScreen
== &gMenuOption
) {
2939 NewPos
= gMenuOption
.BackLink
;
2940 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2943 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2947 // There are more MenuOption needing scrolling up.
2954 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2955 // Don't do this when we are already in the first page.
2957 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2958 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2962 ControlFlag
= CfCheckSelection
;
2964 ASSERT (NewPos
!= NULL
);
2965 if (NewPos
->ForwardLink
== &gMenuOption
) {
2974 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2976 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
2977 Index
= Index
+ NextMenuOption
->Skip
;
2978 Link
= Link
->ForwardLink
;
2979 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2982 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
2984 // Finally we know that NewPos is the last MenuOption can be focused.
2987 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2989 if (Index
- 1 > BottomRow
) {
2991 // Back up the previous option.
2993 Link
= Link
->BackLink
;
2996 // There are more MenuOption needing scrolling down.
3001 // Move to the option in Next page.
3003 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
3007 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3008 // Don't do this when we are already in the last page.
3011 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3012 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3016 ControlFlag
= CfCheckSelection
;
3018 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3019 // to be one that progresses to the next set of op-codes, we need to advance to the last
3020 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3021 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3022 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3023 // the Date/Time op-code.
3025 SavedListEntry
= NewPos
;
3026 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3028 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3029 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3031 NewPos
= NewPos
->ForwardLink
;
3034 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3035 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3037 // We hit the end of MenuOption that can be focused
3038 // so we simply scroll to the first page.
3040 if (Difference
< 0) {
3042 // Scroll to the first page.
3044 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3045 TopOfScreen
= gMenuOption
.ForwardLink
;
3049 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3051 NewPos
= gMenuOption
.ForwardLink
;
3052 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3055 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3057 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3058 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3062 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3065 // An option might be multi-line, so we need to reflect that data in the overall skip value
3067 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
3068 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3070 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3071 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3072 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3073 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3079 // If we are going to scroll, update TopOfScreen
3081 if (Temp
> BottomRow
) {
3084 // Is the current top of screen a zero-advance op-code?
3085 // If so, keep moving forward till we hit a >0 advance op-code
3087 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3090 // If bottom op-code is more than one line or top op-code is more than one line
3092 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3094 // Is the bottom op-code greater than or equal in size to the top op-code?
3096 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3098 // Skip the top op-code
3100 TopOfScreen
= TopOfScreen
->ForwardLink
;
3101 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3103 OldSkipValue
= Difference
;
3105 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3108 // If we have a remainder, skip that many more op-codes until we drain the remainder
3110 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3112 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3114 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3115 TopOfScreen
= TopOfScreen
->ForwardLink
;
3116 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3119 // Since we will act on this op-code in the next routine, and increment the
3120 // SkipValue, set the skips to one less than what is required.
3122 SkipValue
= Difference
- 1;
3126 // Since we will act on this op-code in the next routine, and increment the
3127 // SkipValue, set the skips to one less than what is required.
3129 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3132 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3133 TopOfScreen
= TopOfScreen
->ForwardLink
;
3136 SkipValue
= OldSkipValue
;
3140 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3141 // Let's set a skip flag to smoothly scroll the top of the screen.
3143 if (SavedMenuOption
->Skip
> 1) {
3144 if (SavedMenuOption
== NextMenuOption
) {
3149 } else if (SavedMenuOption
->Skip
== 1) {
3153 TopOfScreen
= TopOfScreen
->ForwardLink
;
3155 } while (SavedMenuOption
->Skip
== 0);
3158 OldSkipValue
= SkipValue
;
3159 } else if (!IsSelectable (NextMenuOption
)) {
3161 // Continue to go down until scroll to next page or the selectable option is found.
3163 ScreenOperation
= UiDown
;
3164 ControlFlag
= CfScreenOperation
;
3167 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3169 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3173 // Scroll to the first page.
3175 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3176 TopOfScreen
= gMenuOption
.ForwardLink
;
3180 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3183 NewPos
= gMenuOption
.ForwardLink
;
3184 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3188 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3190 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3191 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3195 ControlFlag
= CfCheckSelection
;
3200 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
);
3202 if (!EFI_ERROR (Status
)) {
3203 ASSERT(MenuOption
!= NULL
);
3204 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3205 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3208 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3209 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3217 ControlFlag
= CfCheckSelection
;
3218 if (!Selection
->FormEditable
) {
3220 // This Form is not editable, ignore the F9 (reset to default)
3225 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3227 if (!EFI_ERROR (Status
)) {
3228 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3229 Selection
->Statement
= NULL
;
3232 // Show NV update flag on status bar
3234 gNvUpdateRequired
= TRUE
;
3235 gResetRequired
= TRUE
;
3239 case CfUiNoOperation
:
3240 ControlFlag
= CfCheckSelection
;
3244 UiFreeRefreshList ();
3246 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3247 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3248 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3249 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");