2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 LIST_ENTRY gMenuOption
;
18 LIST_ENTRY gMenuList
= INITIALIZE_LIST_HEAD_VARIABLE (gMenuList
);
19 MENU_REFRESH_ENTRY
*gMenuRefreshHead
; // Menu list used for refresh timer opcode.
20 MENU_REFRESH_ENTRY
*gMenuEventGuidRefreshHead
; // Menu list used for refresh event guid opcode.
23 // Search table for UiDisplayMenu()
25 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
56 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
58 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
102 BOOLEAN GetLineByWidthFinished
= FALSE
;
106 Set Buffer to Value for Size bytes.
108 @param Buffer Memory to set.
109 @param Size Number of bytes to set
110 @param Value Value of the set operation.
123 while ((Size
--) != 0) {
130 Initialize Menu option list.
138 InitializeListHead (&gMenuOption
);
143 Free Menu option linked list.
151 UI_MENU_OPTION
*MenuOption
;
153 while (!IsListEmpty (&gMenuOption
)) {
154 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
155 RemoveEntryList (&MenuOption
->Link
);
158 // We allocated space for this description when we did a GetToken, free it here
160 if (MenuOption
->Skip
!= 0) {
162 // For date/time, MenuOption->Description is shared by three Menu Options
163 // Data format : [01/02/2004] [11:22:33]
164 // Line number : 0 0 1 0 0 1
166 FreePool (MenuOption
->Description
);
168 FreePool (MenuOption
);
174 Create a menu with specified formset GUID and form ID, and add it as a child
175 of the given parent menu.
177 @param Parent The parent of menu to be added.
178 @param FormSetGuid The Formset Guid of menu to be added.
179 @param FormId The Form ID of menu to be added.
181 @return A pointer to the newly added menu or NULL if memory is insufficient.
186 IN OUT UI_MENU_LIST
*Parent
,
187 IN EFI_GUID
*FormSetGuid
,
191 UI_MENU_LIST
*MenuList
;
193 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
194 if (MenuList
== NULL
) {
198 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
199 InitializeListHead (&MenuList
->ChildListHead
);
201 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
202 MenuList
->FormId
= FormId
;
203 MenuList
->Parent
= Parent
;
205 if (Parent
== NULL
) {
207 // If parent is not specified, it is the root Form of a Formset
209 InsertTailList (&gMenuList
, &MenuList
->Link
);
211 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
219 Search Menu with given FormId in the parent menu and all its child menus.
221 @param Parent The parent of menu to search.
222 @param FormId The Form ID of menu to search.
224 @return A pointer to menu found or NULL if not found.
228 UiFindChildMenuList (
229 IN UI_MENU_LIST
*Parent
,
235 UI_MENU_LIST
*MenuList
;
237 if (Parent
->FormId
== FormId
) {
241 Link
= GetFirstNode (&Parent
->ChildListHead
);
242 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
243 Child
= UI_MENU_LIST_FROM_LINK (Link
);
245 MenuList
= UiFindChildMenuList (Child
, FormId
);
246 if (MenuList
!= NULL
) {
250 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
258 Search Menu with given FormSetGuid and FormId in all cached menu list.
260 @param FormSetGuid The Formset GUID of the menu to search.
261 @param FormId The Form ID of menu to search.
263 @return A pointer to menu found or NULL if not found.
268 IN EFI_GUID
*FormSetGuid
,
273 UI_MENU_LIST
*MenuList
;
276 Link
= GetFirstNode (&gMenuList
);
277 while (!IsNull (&gMenuList
, Link
)) {
278 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
280 if (CompareGuid (FormSetGuid
, &MenuList
->FormSetGuid
)) {
282 // This is the formset we are looking for, find the form in this formset
284 Child
= UiFindChildMenuList (MenuList
, FormId
);
290 Link
= GetNextNode (&gMenuList
, Link
);
298 Free Menu option linked list.
306 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
308 while (gMenuRefreshHead
!= NULL
) {
309 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
310 FreePool (gMenuRefreshHead
);
311 gMenuRefreshHead
= OldMenuRefreshEntry
;
314 while (gMenuEventGuidRefreshHead
!= NULL
) {
315 OldMenuRefreshEntry
= gMenuEventGuidRefreshHead
->Next
;
316 if (gMenuEventGuidRefreshHead
!= NULL
) {
317 gBS
->CloseEvent(gMenuEventGuidRefreshHead
->Event
);
319 FreePool (gMenuEventGuidRefreshHead
);
320 gMenuEventGuidRefreshHead
= OldMenuRefreshEntry
;
329 @param MenuRefreshEntry Menu refresh structure which has info about the refresh question.
333 IN MENU_REFRESH_ENTRY
*MenuRefreshEntry
336 CHAR16
*OptionString
;
339 UI_MENU_SELECTION
*Selection
;
340 FORM_BROWSER_STATEMENT
*Question
;
342 Selection
= MenuRefreshEntry
->Selection
;
343 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
345 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
346 if (EFI_ERROR (Status
)) {
351 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
353 if (OptionString
!= NULL
) {
355 // If leading spaces on OptionString - remove the spaces
357 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
361 // If old Text is longer than new string, need to clean the old string before paint the newer.
362 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
364 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
365 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
367 MenuRefreshEntry
->CurrentColumn
,
368 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
369 MenuRefreshEntry
->CurrentRow
,
370 MenuRefreshEntry
->CurrentRow
,
371 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
375 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
376 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
377 FreePool (OptionString
);
381 // Question value may be changed, need invoke its Callback()
383 Status
= ProcessCallBackFunction (Selection
, Question
, EFI_BROWSER_ACTION_CHANGING
, FALSE
);
389 Refresh the question which has refresh guid event attribute.
391 @param Event The event which has this function related.
392 @param Context The input context info related to this event or the status code return to the caller.
396 RefreshQuestionNotify(
401 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
402 UI_MENU_SELECTION
*Selection
;
405 // Reset FormPackage update flag
407 mHiiPackageListUpdated
= FALSE
;
409 MenuRefreshEntry
= (MENU_REFRESH_ENTRY
*)Context
;
410 ASSERT (MenuRefreshEntry
!= NULL
);
411 Selection
= MenuRefreshEntry
->Selection
;
413 RefreshQuestion (MenuRefreshEntry
);
415 if (mHiiPackageListUpdated
) {
417 // Package list is updated, force to reparse IFR binary of target Formset
419 mHiiPackageListUpdated
= FALSE
;
420 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
434 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
436 UI_MENU_SELECTION
*Selection
;
438 if (gMenuRefreshHead
!= NULL
) {
440 // call from refresh interval process.
442 MenuRefreshEntry
= gMenuRefreshHead
;
443 Selection
= MenuRefreshEntry
->Selection
;
445 // Reset FormPackage update flag
447 mHiiPackageListUpdated
= FALSE
;
450 Status
= RefreshQuestion (MenuRefreshEntry
);
451 if (EFI_ERROR (Status
)) {
455 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
457 } while (MenuRefreshEntry
!= NULL
);
459 if (mHiiPackageListUpdated
) {
461 // Package list is updated, force to reparse IFR binary of target Formset
463 mHiiPackageListUpdated
= FALSE
;
464 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
474 Wait for a given event to fire, or for an optional timeout to expire.
476 @param Event The event to wait for
477 @param Timeout An optional timeout value in 100 ns units.
478 @param RefreshInterval Menu refresh interval (in seconds).
480 @retval EFI_SUCCESS Event fired before Timeout expired.
481 @retval EFI_TIME_OUT Timout expired before Event fired.
485 UiWaitForSingleEvent (
487 IN UINT64 Timeout
, OPTIONAL
488 IN UINT8 RefreshInterval OPTIONAL
493 EFI_EVENT TimerEvent
;
494 EFI_EVENT WaitList
[2];
498 // Create a timer event
500 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
501 if (!EFI_ERROR (Status
)) {
503 // Set the timer event
512 // Wait for the original event or the timer
515 WaitList
[1] = TimerEvent
;
516 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
517 gBS
->CloseEvent (TimerEvent
);
520 // If the timer expired, change the return to timed out
522 if (!EFI_ERROR (Status
) && Index
== 1) {
523 Status
= EFI_TIMEOUT
;
528 // Update screen every second
530 if (RefreshInterval
== 0) {
531 Timeout
= ONE_SECOND
;
533 Timeout
= RefreshInterval
* ONE_SECOND
;
537 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
540 // Set the timer event
549 // Wait for the original event or the timer
552 WaitList
[1] = TimerEvent
;
553 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
556 // If the timer expired, update anything that needs a refresh and keep waiting
558 if (!EFI_ERROR (Status
) && Index
== 1) {
559 Status
= EFI_TIMEOUT
;
560 if (RefreshInterval
!= 0) {
561 Status
= RefreshForm ();
565 gBS
->CloseEvent (TimerEvent
);
566 } while (Status
== EFI_TIMEOUT
);
574 Add one menu option by specified description and context.
576 @param String String description for this option.
577 @param Handle Hii handle for the package list.
578 @param Statement Statement of this Menu Option.
579 @param NumberOfLines Display lines for this Menu Option.
580 @param MenuItemCount The index for this Option in the Menu.
582 @retval Pointer Pointer to the added Menu Option.
588 IN EFI_HII_HANDLE Handle
,
589 IN FORM_BROWSER_STATEMENT
*Statement
,
590 IN UINT16 NumberOfLines
,
591 IN UINT16 MenuItemCount
594 UI_MENU_OPTION
*MenuOption
;
601 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
603 // Add three MenuOptions for Date/Time
604 // Data format : [01/02/2004] [11:22:33]
605 // Line number : 0 0 1 0 0 1
610 if (Statement
->Storage
== NULL
) {
612 // For RTC type of date/time, set default refresh interval to be 1 second
614 if (Statement
->RefreshInterval
== 0) {
615 Statement
->RefreshInterval
= 1;
620 for (Index
= 0; Index
< Count
; Index
++) {
621 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
624 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
625 MenuOption
->Description
= String
;
626 MenuOption
->Handle
= Handle
;
627 MenuOption
->ThisTag
= Statement
;
628 MenuOption
->EntryNumber
= MenuItemCount
;
632 // Override LineNumber for the MenuOption in Date/Time sequence
634 MenuOption
->Skip
= 1;
636 MenuOption
->Skip
= NumberOfLines
;
638 MenuOption
->Sequence
= Index
;
640 if (Statement
->GrayOutExpression
!= NULL
) {
641 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
644 switch (Statement
->Operand
) {
645 case EFI_IFR_ORDERED_LIST_OP
:
646 case EFI_IFR_ONE_OF_OP
:
647 case EFI_IFR_NUMERIC_OP
:
648 case EFI_IFR_TIME_OP
:
649 case EFI_IFR_DATE_OP
:
650 case EFI_IFR_CHECKBOX_OP
:
651 case EFI_IFR_PASSWORD_OP
:
652 case EFI_IFR_STRING_OP
:
654 // User could change the value of these items
656 MenuOption
->IsQuestion
= TRUE
;
659 case EFI_IFR_TEXT_OP
:
660 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
662 // Initializing GrayOut option as TRUE for Text setup options
663 // so that those options will be Gray in colour and un selectable.
665 MenuOption
->GrayOut
= TRUE
;
669 MenuOption
->IsQuestion
= FALSE
;
673 if ((Statement
->ValueExpression
!= NULL
) ||
674 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
675 MenuOption
->ReadOnly
= TRUE
;
678 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
686 Routine used to abstract a generic dialog interface and return the selected key or string
688 @param NumberOfLines The number of lines for the dialog box
689 @param HotKey Defines whether a single character is parsed
690 (TRUE) and returned in KeyValue or a string is
691 returned in StringBuffer. Two special characters
692 are considered when entering a string, a SCAN_ESC
693 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
694 string input and returns
695 @param MaximumStringSize The maximum size in bytes of a typed in string
696 (each character is a CHAR16) and the minimum
697 string returned is two bytes
698 @param StringBuffer The passed in pointer to the buffer which will
699 hold the typed in string if HotKey is FALSE
700 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
701 @param ... A series of (quantity == NumberOfLines) text
702 strings which will be used to construct the dialog
705 @retval EFI_SUCCESS Displayed dialog and received user interaction
706 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
707 (StringBuffer == NULL) && (HotKey == FALSE))
708 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
714 IN UINTN NumberOfLines
,
716 IN UINTN MaximumStringSize
,
717 OUT CHAR16
*StringBuffer
,
718 OUT EFI_INPUT_KEY
*KeyValue
,
727 CHAR16
*BufferedString
;
734 BOOLEAN SelectionComplete
;
736 UINTN CurrentAttribute
;
737 UINTN DimensionsWidth
;
738 UINTN DimensionsHeight
;
740 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
741 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
743 SelectionComplete
= FALSE
;
745 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
746 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
747 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
750 ASSERT (BufferedString
);
752 VA_START (Marker
, KeyValue
);
755 // Zero the outgoing buffer
757 ZeroMem (StringBuffer
, MaximumStringSize
);
760 if (KeyValue
== NULL
) {
761 return EFI_INVALID_PARAMETER
;
764 if (StringBuffer
== NULL
) {
765 return EFI_INVALID_PARAMETER
;
771 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
776 // Determine the largest string in the dialog box
777 // Notice we are starting with 1 since String is the first string
779 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
780 StackString
= VA_ARG (Marker
, CHAR16
*);
782 if (StackString
[0] == L
' ') {
783 InputOffset
= Count
+ 1;
786 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
788 // Size of the string visually and subtract the width by one for the null-terminator
790 LargestString
= (GetStringWidth (StackString
) / 2);
795 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
796 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
803 VA_START (Marker
, KeyValue
);
804 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
808 // Take the first key typed and report it back?
811 Status
= WaitForKeyStroke (&Key
);
812 ASSERT_EFI_ERROR (Status
);
813 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
817 Status
= WaitForKeyStroke (&Key
);
819 switch (Key
.UnicodeChar
) {
821 switch (Key
.ScanCode
) {
823 FreePool (TempString
);
824 FreePool (BufferedString
);
825 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
826 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
827 return EFI_DEVICE_ERROR
;
835 case CHAR_CARRIAGE_RETURN
:
836 SelectionComplete
= TRUE
;
837 FreePool (TempString
);
838 FreePool (BufferedString
);
839 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
840 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
845 if (StringBuffer
[0] != CHAR_NULL
) {
846 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
847 TempString
[Index
] = StringBuffer
[Index
];
850 // Effectively truncate string by 1 character
852 TempString
[Index
- 1] = CHAR_NULL
;
853 StrCpy (StringBuffer
, TempString
);
858 // If it is the beginning of the string, don't worry about checking maximum limits
860 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
861 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
862 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
863 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
864 KeyPad
[0] = Key
.UnicodeChar
;
865 KeyPad
[1] = CHAR_NULL
;
866 StrCat (StringBuffer
, KeyPad
);
867 StrCat (TempString
, KeyPad
);
870 // If the width of the input string is now larger than the screen, we nee to
871 // adjust the index to start printing portions of the string
873 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
875 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
877 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
878 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
883 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
884 BufferedString
[Count
] = StringBuffer
[Index
];
887 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
890 } while (!SelectionComplete
);
893 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
894 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
899 Draw a pop up windows based on the dimension, number of lines and
902 @param RequestedWidth The width of the pop-up.
903 @param NumberOfLines The number of lines.
904 @param Marker The variable argument list for the list of string to be printed.
909 IN UINTN RequestedWidth
,
910 IN UINTN NumberOfLines
,
922 UINTN DimensionsWidth
;
923 UINTN DimensionsHeight
;
925 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
926 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
928 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
930 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
931 RequestedWidth
= DimensionsWidth
- 2;
935 // Subtract the PopUp width from total Columns, allow for one space extra on
936 // each end plus a border.
938 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
939 End
= Start
+ RequestedWidth
+ 1;
941 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
942 Bottom
= Top
+ NumberOfLines
+ 2;
944 Character
= BOXDRAW_DOWN_RIGHT
;
945 PrintCharAt (Start
, Top
, Character
);
946 Character
= BOXDRAW_HORIZONTAL
;
947 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
948 PrintChar (Character
);
951 Character
= BOXDRAW_DOWN_LEFT
;
952 PrintChar (Character
);
953 Character
= BOXDRAW_VERTICAL
;
956 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
957 String
= VA_ARG (Marker
, CHAR16
*);
960 // This will clear the background of the line - we never know who might have been
961 // here before us. This differs from the next clear in that it used the non-reverse
962 // video for normal printing.
964 if (GetStringWidth (String
) / 2 > 1) {
965 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
969 // Passing in a space results in the assumption that this is where typing will occur
971 if (String
[0] == L
' ') {
972 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
976 // Passing in a NULL results in a blank space
978 if (String
[0] == CHAR_NULL
) {
979 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
983 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
987 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
988 PrintCharAt (Start
, Index
+ 1, Character
);
989 PrintCharAt (End
- 1, Index
+ 1, Character
);
992 Character
= BOXDRAW_UP_RIGHT
;
993 PrintCharAt (Start
, Bottom
- 1, Character
);
994 Character
= BOXDRAW_HORIZONTAL
;
995 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
996 PrintChar (Character
);
999 Character
= BOXDRAW_UP_LEFT
;
1000 PrintChar (Character
);
1004 Draw a pop up windows based on the dimension, number of lines and
1007 @param RequestedWidth The width of the pop-up.
1008 @param NumberOfLines The number of lines.
1009 @param ... A series of text strings that displayed in the pop-up.
1014 CreateMultiStringPopUp (
1015 IN UINTN RequestedWidth
,
1016 IN UINTN NumberOfLines
,
1022 VA_START (Marker
, NumberOfLines
);
1024 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1031 Update status bar on the bottom of menu.
1033 @param Selection Current Selction info.
1034 @param MessageType The type of message to be shown.
1035 @param Flags The flags in Question header.
1036 @param State Set or clear.
1041 IN UI_MENU_SELECTION
*Selection
,
1042 IN UINTN MessageType
,
1048 CHAR16
*NvUpdateMessage
;
1049 CHAR16
*InputErrorMessage
;
1051 FORM_BROWSER_FORMSET
*LocalFormSet
;
1052 FORM_BROWSER_STATEMENT
*Question
;
1054 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1055 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1057 switch (MessageType
) {
1060 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1062 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1063 gScreenDimensions
.BottomRow
- 1,
1068 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1069 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1070 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1073 mInputError
= FALSE
;
1077 case NV_UPDATE_REQUIRED
:
1079 // Global setting support. Show configuration change on every form.
1082 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1084 if (Selection
!= NULL
&& Selection
->Statement
!= NULL
) {
1085 Question
= Selection
->Statement
;
1086 if (Question
->Storage
!= NULL
|| Question
->Operand
== EFI_IFR_DATE_OP
|| Question
->Operand
== EFI_IFR_TIME_OP
) {
1088 // Update only for Question value that need to be saved into Storage.
1090 Selection
->Form
->NvUpdateRequired
= TRUE
;
1094 if (Selection
== NULL
|| IsNvUpdateRequired (Selection
->FormSet
)) {
1095 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1097 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1098 gScreenDimensions
.BottomRow
- 1,
1103 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1104 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1106 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1107 gScreenDimensions
.BottomRow
- 1,
1114 case REFRESH_STATUS_BAR
:
1116 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1119 switch (gBrowserSettingScope
) {
1122 // Check the maintain list to see whether there is any change.
1124 Link
= GetFirstNode (&gBrowserFormSetList
);
1125 while (!IsNull (&gBrowserFormSetList
, Link
)) {
1126 LocalFormSet
= FORM_BROWSER_FORMSET_FROM_LINK (Link
);
1127 if (IsNvUpdateRequired(LocalFormSet
)) {
1128 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1131 Link
= GetNextNode (&gBrowserFormSetList
, Link
);
1136 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1147 FreePool (InputErrorMessage
);
1148 FreePool (NvUpdateMessage
);
1154 Get the supported width for a particular op-code
1156 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1157 @param Handle The handle in the HII database being used
1159 @return Returns the number of CHAR16 characters that is support.
1164 IN FORM_BROWSER_STATEMENT
*Statement
,
1165 IN EFI_HII_HANDLE Handle
1175 // See if the second text parameter is really NULL
1177 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1178 String
= GetToken (Statement
->TextTwo
, Handle
);
1179 Size
= StrLen (String
);
1183 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1184 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1185 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1186 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1187 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1189 // Allow a wide display if text op-code and no secondary text op-code
1191 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1193 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1195 Width
= (UINT16
) gPromptBlockWidth
;
1198 if (Statement
->InSubtitle
) {
1199 Width
-= SUBTITLE_INDENT
;
1202 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1206 Will copy LineWidth amount of a string in the OutputString buffer and return the
1207 number of CHAR16 characters that were copied into the OutputString buffer.
1209 @param InputString String description for this option.
1210 @param LineWidth Width of the desired string to extract in CHAR16
1212 @param Index Where in InputString to start the copy process
1213 @param OutputString Buffer to copy the string into
1215 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1220 IN CHAR16
*InputString
,
1221 IN UINT16 LineWidth
,
1222 IN OUT UINTN
*Index
,
1223 OUT CHAR16
**OutputString
1229 if (GetLineByWidthFinished
) {
1230 GetLineByWidthFinished
= FALSE
;
1237 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1240 // Ensure we have got a valid buffer
1242 if (*OutputString
!= NULL
) {
1245 //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.
1246 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1248 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1249 *Index
= *Index
+ 2;
1253 // Fast-forward the string and see if there is a carriage-return in the string
1255 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1259 // Copy the desired LineWidth of data to the output buffer.
1260 // Also make sure that we don't copy more than the string.
1261 // Also make sure that if there are linefeeds, we account for them.
1263 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1264 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1267 // Convert to CHAR16 value and show that we are done with this operation
1269 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1270 if (LineWidth
!= 0) {
1271 GetLineByWidthFinished
= TRUE
;
1274 if (Count2
== LineWidth
) {
1276 // Rewind the string from the maximum size until we see a space to break the line
1278 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1280 if (LineWidth
== 0) {
1288 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1291 // If currently pointing to a space, increment the index to the first non-space character
1294 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1298 *Index
= (UINT16
) (*Index
+ LineWidth
);
1307 Update display lines for a Menu Option.
1309 @param Selection The user's selection.
1310 @param MenuOption The MenuOption to be checked.
1311 @param OptionalString The option string.
1312 @param SkipValue The number of lins to skip.
1316 UpdateOptionSkipLines (
1317 IN UI_MENU_SELECTION
*Selection
,
1318 IN UI_MENU_OPTION
*MenuOption
,
1319 OUT CHAR16
**OptionalString
,
1327 CHAR16
*OutputString
;
1328 CHAR16
*OptionString
;
1331 OptionString
= *OptionalString
;
1332 OutputString
= NULL
;
1334 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1336 if (OptionString
!= NULL
) {
1337 Width
= (UINT16
) gOptionBlockWidth
;
1341 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1343 // If there is more string to process print on the next row and increment the Skip value
1345 if (StrLen (&OptionString
[Index
]) != 0) {
1346 if (SkipValue
== 0) {
1349 // Since the Number of lines for this menu entry may or may not be reflected accurately
1350 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1351 // some testing to ensure we are keeping this in-sync.
1353 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1355 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1361 FreePool (OutputString
);
1362 if (SkipValue
!= 0) {
1370 *OptionalString
= OptionString
;
1375 Check whether this Menu Option could be highlighted.
1377 This is an internal function.
1379 @param MenuOption The MenuOption to be checked.
1381 @retval TRUE This Menu Option is selectable.
1382 @retval FALSE This Menu Option could not be selected.
1387 UI_MENU_OPTION
*MenuOption
1390 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1391 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1400 Determine if the menu is the last menu that can be selected.
1402 This is an internal function.
1404 @param Direction The scroll direction. False is down. True is up.
1405 @param CurrentPos The current focus.
1407 @return FALSE -- the menu isn't the last menu that can be selected.
1408 @return TRUE -- the menu is the last menu that can be selected.
1413 IN BOOLEAN Direction
,
1414 IN LIST_ENTRY
*CurrentPos
1419 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1421 if (Temp
== &gMenuOption
) {
1430 Move to next selectable statement.
1432 This is an internal function.
1434 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1435 @param CurrentPosition Current position.
1436 @param GapToTop Gap position to top or bottom.
1438 @return The row distance from current MenuOption to next selectable MenuOption.
1442 MoveToNextStatement (
1444 IN OUT LIST_ENTRY
**CurrentPosition
,
1450 UI_MENU_OPTION
*NextMenuOption
;
1451 UI_MENU_OPTION
*PreMenuOption
;
1454 Pos
= *CurrentPosition
;
1455 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1458 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1459 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1461 // Current Position doesn't need to be caculated when go up.
1462 // Caculate distanct at first when go up
1464 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1465 NextMenuOption
= PreMenuOption
;
1468 Distance
+= NextMenuOption
->Skip
;
1470 if (IsSelectable (NextMenuOption
)) {
1473 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1482 // Caculate distanct at later when go down
1484 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1485 NextMenuOption
= PreMenuOption
;
1488 Distance
+= NextMenuOption
->Skip
;
1490 PreMenuOption
= NextMenuOption
;
1491 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1494 *CurrentPosition
= &NextMenuOption
->Link
;
1500 Adjust Data and Time position accordingly.
1501 Data format : [01/02/2004] [11:22:33]
1502 Line number : 0 0 1 0 0 1
1504 This is an internal function.
1506 @param DirectionUp the up or down direction. False is down. True is
1508 @param CurrentPosition Current position. On return: Point to the last
1509 Option (Year or Second) if up; Point to the first
1510 Option (Month or Hour) if down.
1512 @return Return line number to pad. It is possible that we stand on a zero-advance
1513 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1517 AdjustDateAndTimePosition (
1518 IN BOOLEAN DirectionUp
,
1519 IN OUT LIST_ENTRY
**CurrentPosition
1523 LIST_ENTRY
*NewPosition
;
1524 UI_MENU_OPTION
*MenuOption
;
1525 UINTN PadLineNumber
;
1528 NewPosition
= *CurrentPosition
;
1529 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1531 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1532 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1534 // Calculate the distance from current position to the last Date/Time MenuOption
1537 while (MenuOption
->Skip
== 0) {
1539 NewPosition
= NewPosition
->ForwardLink
;
1540 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1544 NewPosition
= *CurrentPosition
;
1547 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1548 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1549 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1550 // checking can be done.
1552 while (Count
++ < 2) {
1553 NewPosition
= NewPosition
->BackLink
;
1557 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1558 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1559 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1560 // checking can be done.
1562 while (Count
-- > 0) {
1563 NewPosition
= NewPosition
->ForwardLink
;
1567 *CurrentPosition
= NewPosition
;
1570 return PadLineNumber
;
1574 Find HII Handle in the HII database associated with given Device Path.
1576 If DevicePath is NULL, then ASSERT.
1578 @param DevicePath Device Path associated with the HII package list
1581 @retval Handle HII package list Handle associated with the Device
1583 @retval NULL Hii Package list handle is not found.
1588 DevicePathToHiiHandle (
1589 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1593 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1598 EFI_HANDLE DriverHandle
;
1599 EFI_HII_HANDLE
*HiiHandles
;
1600 EFI_HII_HANDLE HiiHandle
;
1602 ASSERT (DevicePath
!= NULL
);
1604 TmpDevicePath
= DevicePath
;
1606 // Locate Device Path Protocol handle buffer
1608 Status
= gBS
->LocateDevicePath (
1609 &gEfiDevicePathProtocolGuid
,
1613 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1618 // Retrieve all HII Handles from HII database
1620 BufferSize
= 0x1000;
1621 HiiHandles
= AllocatePool (BufferSize
);
1622 ASSERT (HiiHandles
!= NULL
);
1623 Status
= mHiiDatabase
->ListPackageLists (
1625 EFI_HII_PACKAGE_TYPE_ALL
,
1630 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1631 FreePool (HiiHandles
);
1632 HiiHandles
= AllocatePool (BufferSize
);
1633 ASSERT (HiiHandles
!= NULL
);
1635 Status
= mHiiDatabase
->ListPackageLists (
1637 EFI_HII_PACKAGE_TYPE_ALL
,
1644 if (EFI_ERROR (Status
)) {
1645 FreePool (HiiHandles
);
1650 // Search Hii Handle by Driver Handle
1653 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1654 for (Index
= 0; Index
< HandleCount
; Index
++) {
1655 Status
= mHiiDatabase
->GetPackageListHandle (
1660 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1661 HiiHandle
= HiiHandles
[Index
];
1666 FreePool (HiiHandles
);
1671 Process the goto op code, update the info in the selection structure.
1673 @param Statement The statement belong to goto op code.
1674 @param Selection The selection info.
1675 @param Repaint Whether need to repaint the menu.
1676 @param NewLine Whether need to create new line.
1678 @retval EFI_SUCCESS The menu process successfully.
1679 @return Other value if the process failed.
1683 IN OUT FORM_BROWSER_STATEMENT
*Statement
,
1684 IN OUT UI_MENU_SELECTION
*Selection
,
1685 OUT BOOLEAN
*Repaint
,
1686 OUT BOOLEAN
*NewLine
1691 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1693 UINT8
*DevicePathBuffer
;
1696 FORM_BROWSER_FORM
*RefForm
;
1699 UI_MENU_LIST
*MenuList
;
1701 Status
= EFI_SUCCESS
;
1703 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0) {
1704 if (Selection
->Form
->ModalForm
) {
1708 // Goto another Hii Package list
1710 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1712 StringPtr
= GetToken (Statement
->HiiValue
.Value
.ref
.DevicePath
, Selection
->FormSet
->HiiHandle
);
1713 if (StringPtr
== NULL
) {
1715 // No device path string not found, exit
1717 Selection
->Action
= UI_ACTION_EXIT
;
1718 Selection
->Statement
= NULL
;
1721 BufferSize
= StrLen (StringPtr
) / 2;
1722 DevicePath
= AllocatePool (BufferSize
);
1723 ASSERT (DevicePath
!= NULL
);
1726 // Convert from Device Path String to DevicePath Buffer in the reverse order.
1728 DevicePathBuffer
= (UINT8
*) DevicePath
;
1729 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
1730 TemStr
[0] = StringPtr
[Index
];
1731 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
1732 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
1734 // Invalid Hex Char as the tail.
1738 if ((Index
& 1) == 0) {
1739 DevicePathBuffer
[Index
/2] = DigitUint8
;
1741 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
1745 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
1746 if (Selection
->Handle
== NULL
) {
1748 // If target Hii Handle not found, exit
1750 Selection
->Action
= UI_ACTION_EXIT
;
1751 Selection
->Statement
= NULL
;
1755 FreePool (StringPtr
);
1756 FreePool (DevicePath
);
1758 CopyMem (&Selection
->FormSetGuid
,&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1759 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1760 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1761 } else if (!CompareGuid (&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, &gZeroGuid
)) {
1762 if (Selection
->Form
->ModalForm
) {
1766 // Goto another Formset, check for uncommitted data
1768 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1770 CopyMem (&Selection
->FormSetGuid
, &Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1771 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1772 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1773 } else if (Statement
->HiiValue
.Value
.ref
.FormId
!= 0) {
1775 // Check whether target From is suppressed.
1777 RefForm
= IdToForm (Selection
->FormSet
, Statement
->HiiValue
.Value
.ref
.FormId
);
1779 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
1780 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
1781 if (EFI_ERROR (Status
)) {
1785 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
1787 // Form is suppressed.
1790 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
1791 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1792 if (Repaint
!= NULL
) {
1800 // Goto another form inside this formset,
1802 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1805 // Link current form so that we can always go back when someone hits the ESC
1807 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->HiiValue
.Value
.ref
.FormId
);
1808 if (MenuList
== NULL
&& Selection
->CurrentMenu
!= NULL
) {
1809 MenuList
= UiAddMenuList (Selection
->CurrentMenu
, &Selection
->FormSetGuid
, Statement
->HiiValue
.Value
.ref
.FormId
);
1812 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1813 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1814 } else if (Statement
->HiiValue
.Value
.ref
.QuestionId
!= 0) {
1816 // Goto another Question
1818 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1820 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1821 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1823 if (Repaint
!= NULL
) {
1826 if (NewLine
!= NULL
) {
1831 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1832 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1840 Display menu and wait for user to select one menu option, then return it.
1841 If AutoBoot is enabled, then if user doesn't select any option,
1842 after period of time, it will automatically return the first menu option.
1844 @param Selection Menu selection.
1846 @retval EFI_SUCESSS This function always return successfully for now.
1851 IN OUT UI_MENU_SELECTION
*Selection
1857 UINTN DistanceValue
;
1869 CHAR16
*OptionString
;
1870 CHAR16
*OutputString
;
1871 CHAR16
*FormattedString
;
1877 BOOLEAN InitializedFlag
;
1882 LIST_ENTRY
*TopOfScreen
;
1883 LIST_ENTRY
*SavedListEntry
;
1884 UI_MENU_OPTION
*MenuOption
;
1885 UI_MENU_OPTION
*NextMenuOption
;
1886 UI_MENU_OPTION
*SavedMenuOption
;
1887 UI_MENU_OPTION
*PreviousMenuOption
;
1888 UI_CONTROL_FLAG ControlFlag
;
1889 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1890 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1891 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
1892 UI_SCREEN_OPERATION ScreenOperation
;
1893 UINT8 MinRefreshInterval
;
1895 FORM_BROWSER_STATEMENT
*Statement
;
1896 UI_MENU_LIST
*CurrentMenu
;
1897 UINTN ModalSkipColumn
;
1898 BROWSER_HOT_KEY
*HotKey
;
1900 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1902 Status
= EFI_SUCCESS
;
1903 FormattedString
= NULL
;
1904 OptionString
= NULL
;
1905 ScreenOperation
= UiNoOperation
;
1907 MinRefreshInterval
= 0;
1910 OutputString
= NULL
;
1915 MenuRefreshEntry
= gMenuRefreshHead
;
1917 NextMenuOption
= NULL
;
1918 PreviousMenuOption
= NULL
;
1919 SavedMenuOption
= NULL
;
1921 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
1923 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1925 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1926 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1927 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1929 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1930 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1933 if (Selection
->Form
->ModalForm
) {
1934 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1936 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1939 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- gFooterHeight
- SCROLL_ARROW_HEIGHT
- 1;
1941 Selection
->TopRow
= TopRow
;
1942 Selection
->BottomRow
= BottomRow
;
1943 Selection
->PromptCol
= Col
;
1944 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1945 Selection
->Statement
= NULL
;
1947 TopOfScreen
= gMenuOption
.ForwardLink
;
1952 // Find current Menu
1954 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1955 if (CurrentMenu
== NULL
) {
1957 // Current menu not found, add it to the menu tree
1959 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1961 ASSERT (CurrentMenu
!= NULL
);
1962 Selection
->CurrentMenu
= CurrentMenu
;
1964 if (Selection
->QuestionId
== 0) {
1966 // Highlight not specified, fetch it from cached menu
1968 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1969 Selection
->Sequence
= CurrentMenu
->Sequence
;
1973 // Init option as the current user's selection
1975 InitializedFlag
= TRUE
;
1976 NewPos
= gMenuOption
.ForwardLink
;
1978 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1979 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1981 ControlFlag
= CfInitialization
;
1982 Selection
->Action
= UI_ACTION_NONE
;
1984 switch (ControlFlag
) {
1985 case CfInitialization
:
1986 if (IsListEmpty (&gMenuOption
)) {
1987 ControlFlag
= CfReadKey
;
1989 ControlFlag
= CfCheckSelection
;
1993 case CfCheckSelection
:
1994 if (Selection
->Action
!= UI_ACTION_NONE
) {
1995 ControlFlag
= CfExit
;
1997 ControlFlag
= CfRepaint
;
2002 ControlFlag
= CfRefreshHighLight
;
2012 Temp
= (UINTN
) SkipValue
;
2013 Temp2
= (UINTN
) SkipValue
;
2015 if (Selection
->Form
->ModalForm
) {
2017 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
2018 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
2019 TopRow
- SCROLL_ARROW_HEIGHT
,
2020 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2021 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2025 LocalScreen
.LeftColumn
,
2026 LocalScreen
.RightColumn
,
2027 TopRow
- SCROLL_ARROW_HEIGHT
,
2028 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2029 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2032 UiFreeRefreshList ();
2033 MinRefreshInterval
= 0;
2035 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2036 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2037 MenuOption
->Row
= Row
;
2038 MenuOption
->Col
= Col
;
2039 if (Selection
->Form
->ModalForm
) {
2040 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
2042 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2045 Statement
= MenuOption
->ThisTag
;
2046 if (Statement
->InSubtitle
) {
2047 MenuOption
->Col
+= SUBTITLE_INDENT
;
2050 if (MenuOption
->GrayOut
) {
2051 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2053 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2054 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2058 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2061 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
2063 // Print Arrow for Goto button.
2066 MenuOption
->Col
- 2,
2069 GEOMETRICSHAPE_RIGHT_TRIANGLE
2073 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2074 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2075 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
2078 // If there is more string to process print on the next row and increment the Skip value
2080 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2086 FreePool (OutputString
);
2095 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2096 if (EFI_ERROR (Status
)) {
2098 // Repaint to clear possible error prompt pop-up
2102 ControlFlag
= CfRepaint
;
2106 if (OptionString
!= NULL
) {
2107 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2109 // If leading spaces on OptionString - remove the spaces
2111 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
2112 MenuOption
->OptCol
++;
2115 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2116 OptionString
[Count
] = OptionString
[Index
];
2120 OptionString
[Count
] = CHAR_NULL
;
2123 Width
= (UINT16
) gOptionBlockWidth
;
2126 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2127 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2128 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2131 // If there is more string to process print on the next row and increment the Skip value
2133 if (StrLen (&OptionString
[Index
]) != 0) {
2137 // Since the Number of lines for this menu entry may or may not be reflected accurately
2138 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2139 // some testing to ensure we are keeping this in-sync.
2141 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2143 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2149 FreePool (OutputString
);
2158 FreePool (OptionString
);
2162 // If Question has refresh guid, register the op-code.
2164 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
2165 if (gMenuEventGuidRefreshHead
== NULL
) {
2166 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2167 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
2169 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
2170 while (MenuUpdateEntry
->Next
!= NULL
) {
2171 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2173 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2174 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2176 ASSERT (MenuUpdateEntry
!= NULL
);
2177 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
2178 ASSERT (!EFI_ERROR (Status
));
2179 MenuUpdateEntry
->MenuOption
= MenuOption
;
2180 MenuUpdateEntry
->Selection
= Selection
;
2181 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
2182 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
2183 if (MenuOption
->GrayOut
) {
2184 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2186 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2191 // If Question request refresh, register the op-code
2193 if (Statement
->RefreshInterval
!= 0) {
2195 // Menu will be refreshed at minimal interval of all Questions
2196 // which have refresh request
2198 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
2199 MinRefreshInterval
= Statement
->RefreshInterval
;
2202 if (gMenuRefreshHead
== NULL
) {
2203 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2204 gMenuRefreshHead
= MenuRefreshEntry
;
2206 MenuRefreshEntry
= gMenuRefreshHead
;
2207 while (MenuRefreshEntry
->Next
!= NULL
) {
2208 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2210 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2211 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2213 ASSERT (MenuRefreshEntry
!= NULL
);
2214 MenuRefreshEntry
->MenuOption
= MenuOption
;
2215 MenuRefreshEntry
->Selection
= Selection
;
2216 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2217 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2218 if (MenuOption
->GrayOut
) {
2219 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2221 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2226 // If this is a text op with secondary text information
2228 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2229 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2231 Width
= (UINT16
) gOptionBlockWidth
;
2234 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
2235 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2236 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2239 // If there is more string to process print on the next row and increment the Skip value
2241 if (StrLen (&StringPtr
[Index
]) != 0) {
2245 // Since the Number of lines for this menu entry may or may not be reflected accurately
2246 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2247 // some testing to ensure we are keeping this in-sync.
2249 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2251 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2257 FreePool (OutputString
);
2264 FreePool (StringPtr
);
2266 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2269 // Need to handle the bottom of the display
2271 if (MenuOption
->Skip
> 1) {
2272 Row
+= MenuOption
->Skip
- SkipValue
;
2275 Row
+= MenuOption
->Skip
;
2278 if (Row
> BottomRow
) {
2279 if (!ValueIsScroll (FALSE
, Link
)) {
2283 Row
= BottomRow
+ 1;
2288 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2293 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2295 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2296 TopRow
- SCROLL_ARROW_HEIGHT
,
2300 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2304 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2306 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2307 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2311 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2318 case CfRefreshHighLight
:
2320 // MenuOption: Last menu option that need to remove hilight
2321 // MenuOption is set to NULL in Repaint
2322 // NewPos: Current menu option that need to hilight
2324 ControlFlag
= CfUpdateHelpString
;
2325 if (InitializedFlag
) {
2326 InitializedFlag
= FALSE
;
2327 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2331 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2332 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2334 SavedValue
= Repaint
;
2337 if (Selection
->QuestionId
!= 0) {
2338 NewPos
= gMenuOption
.ForwardLink
;
2339 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2341 while ((SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
||
2342 SavedMenuOption
->Sequence
!= Selection
->Sequence
) &&
2343 NewPos
->ForwardLink
!= &gMenuOption
) {
2344 NewPos
= NewPos
->ForwardLink
;
2345 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2347 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2349 // Target Question found, find its MenuOption
2353 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2354 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2355 Index
+= SavedMenuOption
->Skip
;
2356 Link
= Link
->ForwardLink
;
2359 if (Link
!= NewPos
|| Index
> BottomRow
) {
2361 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2364 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2365 Link
= Link
->BackLink
;
2366 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2367 Index
+= SavedMenuOption
->Skip
;
2369 TopOfScreen
= Link
->ForwardLink
;
2373 ControlFlag
= CfRepaint
;
2378 // Target Question not found, highlight the default menu option
2380 NewPos
= TopOfScreen
;
2383 Selection
->QuestionId
= 0;
2386 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2387 if (MenuOption
!= NULL
) {
2389 // Remove highlight on last Menu Option
2391 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2392 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2393 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2394 if (OptionString
!= NULL
) {
2395 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2396 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2399 // If leading spaces on OptionString - remove the spaces
2401 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2404 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2405 OptionString
[Count
] = OptionString
[Index
];
2409 OptionString
[Count
] = CHAR_NULL
;
2412 Width
= (UINT16
) gOptionBlockWidth
;
2413 OriginalRow
= MenuOption
->Row
;
2415 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2416 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2417 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2420 // If there is more string to process print on the next row and increment the Skip value
2422 if (StrLen (&OptionString
[Index
]) != 0) {
2426 FreePool (OutputString
);
2429 MenuOption
->Row
= OriginalRow
;
2431 FreePool (OptionString
);
2434 if (MenuOption
->GrayOut
) {
2435 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2436 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2437 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2440 OriginalRow
= MenuOption
->Row
;
2441 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2443 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2444 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2445 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2448 // If there is more string to process print on the next row and increment the Skip value
2450 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2454 FreePool (OutputString
);
2457 MenuOption
->Row
= OriginalRow
;
2458 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2464 // This is the current selected statement
2466 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2467 Statement
= MenuOption
->ThisTag
;
2468 Selection
->Statement
= Statement
;
2469 if (!IsSelectable (MenuOption
)) {
2470 Repaint
= SavedValue
;
2471 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2476 // Record highlight for current menu
2478 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2479 CurrentMenu
->Sequence
= MenuOption
->Sequence
;
2482 // Set reverse attribute
2484 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2485 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2488 // Assuming that we have a refresh linked-list created, lets annotate the
2489 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2490 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2492 if (gMenuRefreshHead
!= NULL
) {
2493 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2494 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2495 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2497 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2499 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2500 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2505 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2506 if (OptionString
!= NULL
) {
2507 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2509 // If leading spaces on OptionString - remove the spaces
2511 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2514 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2515 OptionString
[Count
] = OptionString
[Index
];
2519 OptionString
[Count
] = CHAR_NULL
;
2521 Width
= (UINT16
) gOptionBlockWidth
;
2523 OriginalRow
= MenuOption
->Row
;
2525 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2526 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2527 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2530 // If there is more string to process print on the next row and increment the Skip value
2532 if (StrLen (&OptionString
[Index
]) != 0) {
2536 FreePool (OutputString
);
2539 MenuOption
->Row
= OriginalRow
;
2541 FreePool (OptionString
);
2544 OriginalRow
= MenuOption
->Row
;
2546 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2548 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2549 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2550 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2553 // If there is more string to process print on the next row and increment the Skip value
2555 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2559 FreePool (OutputString
);
2562 MenuOption
->Row
= OriginalRow
;
2567 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2570 // Clear reverse attribute
2572 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2575 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2576 // if we didn't break halfway when process CfRefreshHighLight.
2578 Repaint
= SavedValue
;
2581 case CfUpdateHelpString
:
2582 ControlFlag
= CfPrepareToReadKey
;
2583 if (Selection
->Form
->ModalForm
) {
2587 if (Repaint
|| NewLine
) {
2589 // Don't print anything if it is a NULL help token
2591 ASSERT(MenuOption
!= NULL
);
2592 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2595 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2598 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2600 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2602 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2604 // Pad String with spaces to simulate a clearing of the previous line
2606 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2607 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2611 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2613 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2618 // Reset this flag every time we finish using it.
2624 case CfPrepareToReadKey
:
2625 ControlFlag
= CfReadKey
;
2626 ScreenOperation
= UiNoOperation
;
2630 ControlFlag
= CfScreenOperation
;
2633 // Wait for user's selection
2636 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2637 } while (Status
== EFI_TIMEOUT
);
2639 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2641 // IFR is updated in Callback of refresh opcode, re-parse it
2643 ControlFlag
= CfCheckSelection
;
2644 Selection
->Statement
= NULL
;
2648 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2650 // If we encounter error, continue to read another key in.
2652 if (EFI_ERROR (Status
)) {
2653 ControlFlag
= CfReadKey
;
2657 switch (Key
.UnicodeChar
) {
2658 case CHAR_CARRIAGE_RETURN
:
2659 ScreenOperation
= UiSelect
;
2664 // We will push the adjustment of these numeric values directly to the input handler
2665 // NOTE: we won't handle manual input numeric
2670 // If the screen has no menu items, and the user didn't select UiReset
2671 // ignore the selection and go back to reading keys.
2673 if(IsListEmpty (&gMenuOption
)) {
2674 ControlFlag
= CfReadKey
;
2678 ASSERT(MenuOption
!= NULL
);
2679 Statement
= MenuOption
->ThisTag
;
2680 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2681 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2682 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2684 if (Key
.UnicodeChar
== '+') {
2685 gDirection
= SCAN_RIGHT
;
2687 gDirection
= SCAN_LEFT
;
2689 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2690 if (EFI_ERROR (Status
)) {
2692 // Repaint to clear possible error prompt pop-up
2697 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2699 if (OptionString
!= NULL
) {
2700 FreePool (OptionString
);
2706 ScreenOperation
= UiUp
;
2711 ScreenOperation
= UiDown
;
2715 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2717 // If the screen has no menu items, and the user didn't select UiReset
2718 // ignore the selection and go back to reading keys.
2720 if(IsListEmpty (&gMenuOption
)) {
2721 ControlFlag
= CfReadKey
;
2725 ASSERT(MenuOption
!= NULL
);
2726 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2727 ScreenOperation
= UiSelect
;
2733 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2734 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2735 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2740 if (Selection
->Form
->ModalForm
&& (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2742 // ModalForm has no ESC key and Hot Key.
2744 ControlFlag
= CfReadKey
;
2745 } else if (Index
== mScanCodeNumber
) {
2747 // Check whether Key matches the registered hot key.
2750 if ((gBrowserSettingScope
== SystemLevel
) || (gFunctionKeySetting
!= NONE_FUNCTION_KEY_SETTING
)) {
2751 HotKey
= GetHotKeyFromRegisterList (&Key
);
2753 if (HotKey
!= NULL
) {
2754 ScreenOperation
= UiHotKey
;
2761 case CfScreenOperation
:
2762 if (ScreenOperation
!= UiReset
) {
2764 // If the screen has no menu items, and the user didn't select UiReset
2765 // ignore the selection and go back to reading keys.
2767 if (IsListEmpty (&gMenuOption
)) {
2768 ControlFlag
= CfReadKey
;
2774 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2777 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2778 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2785 ControlFlag
= CfCheckSelection
;
2787 ASSERT(MenuOption
!= NULL
);
2788 Statement
= MenuOption
->ThisTag
;
2789 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2794 // Keep highlight on current MenuOption
2796 Selection
->QuestionId
= Statement
->QuestionId
;
2798 switch (Statement
->Operand
) {
2799 case EFI_IFR_REF_OP
:
2800 ProcessGotoOpCode(Statement
, Selection
, &Repaint
, &NewLine
);
2803 case EFI_IFR_ACTION_OP
:
2805 // Process the Config string <ConfigResp>
2807 Status
= ProcessQuestionConfig (Selection
, Statement
);
2809 if (EFI_ERROR (Status
)) {
2814 // The action button may change some Question value, so refresh the form
2816 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2819 case EFI_IFR_RESET_BUTTON_OP
:
2821 // Reset Question to default value specified by DefaultId
2823 ControlFlag
= CfUiDefault
;
2824 DefaultId
= Statement
->DefaultId
;
2829 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2831 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2832 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2834 if (EFI_ERROR (Status
)) {
2837 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2839 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2842 if (OptionString
!= NULL
) {
2843 FreePool (OptionString
);
2851 // We come here when someone press ESC
2853 ControlFlag
= CfCheckSelection
;
2854 FindNextMenu (Selection
, &Repaint
, &NewLine
);
2858 ControlFlag
= CfCheckSelection
;
2859 ASSERT(MenuOption
!= NULL
);
2860 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2861 if (MenuOption
->Sequence
!= 0) {
2863 // In the middle or tail of the Date/Time op-code set, go left.
2865 ASSERT(NewPos
!= NULL
);
2866 NewPos
= NewPos
->BackLink
;
2872 ControlFlag
= CfCheckSelection
;
2873 ASSERT(MenuOption
!= NULL
);
2874 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2875 if (MenuOption
->Sequence
!= 2) {
2877 // In the middle or tail of the Date/Time op-code set, go left.
2879 ASSERT(NewPos
!= NULL
);
2880 NewPos
= NewPos
->ForwardLink
;
2886 ControlFlag
= CfCheckSelection
;
2888 SavedListEntry
= NewPos
;
2890 ASSERT(NewPos
!= NULL
);
2892 // Adjust Date/Time position before we advance forward.
2894 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2895 if (NewPos
->BackLink
!= &gMenuOption
) {
2896 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2897 ASSERT (MenuOption
!= NULL
);
2899 NewPos
= NewPos
->BackLink
;
2901 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2902 DistanceValue
= PreviousMenuOption
->Skip
;
2904 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2905 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2907 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2909 if (Difference
< 0) {
2911 // We hit the begining MenuOption that can be focused
2912 // so we simply scroll to the top.
2914 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2915 TopOfScreen
= gMenuOption
.ForwardLink
;
2919 // Scroll up to the last page when we have arrived at top page.
2921 NewPos
= &gMenuOption
;
2922 TopOfScreen
= &gMenuOption
;
2923 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2924 ScreenOperation
= UiPageUp
;
2925 ControlFlag
= CfScreenOperation
;
2928 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2930 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2932 TopOfScreen
= NewPos
;
2936 } else if (!IsSelectable (NextMenuOption
)) {
2938 // Continue to go up until scroll to next page or the selectable option is found.
2940 ScreenOperation
= UiUp
;
2941 ControlFlag
= CfScreenOperation
;
2945 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2947 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2948 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2949 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2950 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2953 // Scroll up to the last page.
2955 NewPos
= &gMenuOption
;
2956 TopOfScreen
= &gMenuOption
;
2957 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2958 ScreenOperation
= UiPageUp
;
2959 ControlFlag
= CfScreenOperation
;
2964 ControlFlag
= CfCheckSelection
;
2966 ASSERT(NewPos
!= NULL
);
2967 if (NewPos
->BackLink
== &gMenuOption
) {
2977 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2978 Link
= Link
->BackLink
;
2979 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2980 if (Index
< PreviousMenuOption
->Skip
) {
2984 Index
= Index
- PreviousMenuOption
->Skip
;
2987 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2988 if (TopOfScreen
== &gMenuOption
) {
2989 TopOfScreen
= gMenuOption
.ForwardLink
;
2990 NewPos
= gMenuOption
.BackLink
;
2991 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2993 } else if (TopOfScreen
!= Link
) {
2996 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2999 // Finally we know that NewPos is the last MenuOption can be focused.
3003 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3006 if (Index
+ 1 < TopRow
) {
3008 // Back up the previous option.
3010 Link
= Link
->ForwardLink
;
3014 // Move to the option in Next page.
3016 if (TopOfScreen
== &gMenuOption
) {
3017 NewPos
= gMenuOption
.BackLink
;
3018 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
3021 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3025 // There are more MenuOption needing scrolling up.
3032 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3033 // Don't do this when we are already in the first page.
3035 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3036 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3040 ControlFlag
= CfCheckSelection
;
3042 ASSERT (NewPos
!= NULL
);
3043 if (NewPos
->ForwardLink
== &gMenuOption
) {
3052 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3054 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
3055 Index
= Index
+ NextMenuOption
->Skip
;
3056 Link
= Link
->ForwardLink
;
3057 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3060 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
3062 // Finally we know that NewPos is the last MenuOption can be focused.
3065 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
3067 if (Index
- 1 > BottomRow
) {
3069 // Back up the previous option.
3071 Link
= Link
->BackLink
;
3074 // There are more MenuOption needing scrolling down.
3079 // Move to the option in Next page.
3081 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
3085 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3086 // Don't do this when we are already in the last page.
3089 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3090 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3094 ControlFlag
= CfCheckSelection
;
3096 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3097 // to be one that progresses to the next set of op-codes, we need to advance to the last
3098 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3099 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3100 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3101 // the Date/Time op-code.
3103 SavedListEntry
= NewPos
;
3104 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3106 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3107 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3109 NewPos
= NewPos
->ForwardLink
;
3112 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3113 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3115 // We hit the end of MenuOption that can be focused
3116 // so we simply scroll to the first page.
3118 if (Difference
< 0) {
3120 // Scroll to the first page.
3122 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3123 TopOfScreen
= gMenuOption
.ForwardLink
;
3127 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3129 NewPos
= gMenuOption
.ForwardLink
;
3130 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3133 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3135 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3136 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3140 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3143 // An option might be multi-line, so we need to reflect that data in the overall skip value
3145 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
3146 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3148 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3149 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3150 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3151 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3157 // If we are going to scroll, update TopOfScreen
3159 if (Temp
> BottomRow
) {
3162 // Is the current top of screen a zero-advance op-code?
3163 // If so, keep moving forward till we hit a >0 advance op-code
3165 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3168 // If bottom op-code is more than one line or top op-code is more than one line
3170 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3172 // Is the bottom op-code greater than or equal in size to the top op-code?
3174 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3176 // Skip the top op-code
3178 TopOfScreen
= TopOfScreen
->ForwardLink
;
3179 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3181 OldSkipValue
= Difference
;
3183 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3186 // If we have a remainder, skip that many more op-codes until we drain the remainder
3188 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3190 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3192 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3193 TopOfScreen
= TopOfScreen
->ForwardLink
;
3194 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3197 // Since we will act on this op-code in the next routine, and increment the
3198 // SkipValue, set the skips to one less than what is required.
3200 SkipValue
= Difference
- 1;
3204 // Since we will act on this op-code in the next routine, and increment the
3205 // SkipValue, set the skips to one less than what is required.
3207 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3210 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3211 TopOfScreen
= TopOfScreen
->ForwardLink
;
3214 SkipValue
= OldSkipValue
;
3218 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3219 // Let's set a skip flag to smoothly scroll the top of the screen.
3221 if (SavedMenuOption
->Skip
> 1) {
3222 if (SavedMenuOption
== NextMenuOption
) {
3227 } else if (SavedMenuOption
->Skip
== 1) {
3231 TopOfScreen
= TopOfScreen
->ForwardLink
;
3233 } while (SavedMenuOption
->Skip
== 0);
3236 OldSkipValue
= SkipValue
;
3237 } else if (!IsSelectable (NextMenuOption
)) {
3239 // Continue to go down until scroll to next page or the selectable option is found.
3241 ScreenOperation
= UiDown
;
3242 ControlFlag
= CfScreenOperation
;
3245 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3247 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3251 // Scroll to the first page.
3253 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3254 TopOfScreen
= gMenuOption
.ForwardLink
;
3258 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3261 NewPos
= gMenuOption
.ForwardLink
;
3262 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3266 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3268 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3269 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3273 ControlFlag
= CfCheckSelection
;
3275 Status
= EFI_SUCCESS
;
3277 // Discard changes. After it, no NV flag is showed.
3279 if ((HotKey
->Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
3280 Status
= DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3281 if (!EFI_ERROR (Status
)) {
3282 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3283 Selection
->Statement
= NULL
;
3284 gResetRequired
= FALSE
;
3287 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDiscardFailed
, gPressEnter
, gEmptyString
);
3288 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3290 // Still show current page.
3292 Selection
->Action
= UI_ACTION_NONE
;
3300 // Reterieve default setting. After it. NV flag will be showed.
3302 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3303 Status
= ExtractDefault (Selection
->FormSet
, Selection
->Form
, HotKey
->DefaultId
, gBrowserSettingScope
);
3304 if (!EFI_ERROR (Status
)) {
3305 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3306 Selection
->Statement
= NULL
;
3307 gResetRequired
= TRUE
;
3310 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDefaultFailed
, gPressEnter
, gEmptyString
);
3311 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3313 // Still show current page.
3315 Selection
->Action
= UI_ACTION_NONE
;
3323 // Save changes. After it, no NV flag is showed.
3325 if ((HotKey
->Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
3326 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3327 if (!EFI_ERROR (Status
)) {
3328 ASSERT(MenuOption
!= NULL
);
3329 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3330 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3333 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3334 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3336 // Still show current page.
3338 Selection
->Action
= UI_ACTION_NONE
;
3346 // Set Reset required Flag
3348 if ((HotKey
->Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
3349 gResetRequired
= TRUE
;
3355 if ((HotKey
->Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
3357 // Form Exit without saving, Similar to ESC Key.
3358 // FormSet Exit without saving, Exit SendForm.
3359 // System Exit without saving, CallExitHandler and Exit SendForm.
3361 DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3362 if (gBrowserSettingScope
== FormLevel
) {
3363 ControlFlag
= CfUiReset
;
3364 } else if (gBrowserSettingScope
== FormSetLevel
) {
3365 Selection
->Action
= UI_ACTION_EXIT
;
3366 } else if (gBrowserSettingScope
== SystemLevel
) {
3367 if (ExitHandlerFunction
!= NULL
) {
3368 ExitHandlerFunction ();
3370 Selection
->Action
= UI_ACTION_EXIT
;
3372 Selection
->Statement
= NULL
;
3377 ControlFlag
= CfCheckSelection
;
3379 // Reset to default value for all forms in the whole system.
3381 Status
= ExtractDefault (Selection
->FormSet
, NULL
, DefaultId
, FormSetLevel
);
3383 if (!EFI_ERROR (Status
)) {
3384 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3385 Selection
->Statement
= NULL
;
3386 gResetRequired
= TRUE
;
3390 case CfUiNoOperation
:
3391 ControlFlag
= CfCheckSelection
;
3395 UiFreeRefreshList ();
3397 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3398 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3399 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3400 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");