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.
1314 UpdateOptionSkipLines (
1315 IN UI_MENU_SELECTION
*Selection
,
1316 IN UI_MENU_OPTION
*MenuOption
1323 CHAR16
*OutputString
;
1324 CHAR16
*OptionString
;
1327 OptionString
= NULL
;
1328 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1330 if (OptionString
!= NULL
) {
1331 Width
= (UINT16
) gOptionBlockWidth
;
1335 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1337 // If there is more string to process print on the next row and increment the Skip value
1339 if (StrLen (&OptionString
[Index
]) != 0) {
1342 // Since the Number of lines for this menu entry may or may not be reflected accurately
1343 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1344 // some testing to ensure we are keeping this in-sync.
1346 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1348 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1353 FreePool (OutputString
);
1359 if (OptionString
!= NULL
) {
1360 FreePool (OptionString
);
1366 Check whether this Menu Option could be highlighted.
1368 This is an internal function.
1370 @param MenuOption The MenuOption to be checked.
1372 @retval TRUE This Menu Option is selectable.
1373 @retval FALSE This Menu Option could not be selected.
1378 UI_MENU_OPTION
*MenuOption
1381 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1382 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1391 Determine if the menu is the last menu that can be selected.
1393 This is an internal function.
1395 @param Direction The scroll direction. False is down. True is up.
1396 @param CurrentPos The current focus.
1398 @return FALSE -- the menu isn't the last menu that can be selected.
1399 @return TRUE -- the menu is the last menu that can be selected.
1404 IN BOOLEAN Direction
,
1405 IN LIST_ENTRY
*CurrentPos
1410 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1412 if (Temp
== &gMenuOption
) {
1421 Move to next selectable statement.
1423 This is an internal function.
1425 @param Selection Menu selection.
1426 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1427 @param CurrentPosition Current position.
1428 @param GapToTop Gap position to top or bottom.
1430 @return The row distance from current MenuOption to next selectable MenuOption.
1434 MoveToNextStatement (
1435 IN UI_MENU_SELECTION
*Selection
,
1437 IN OUT LIST_ENTRY
**CurrentPosition
,
1443 UI_MENU_OPTION
*NextMenuOption
;
1444 UI_MENU_OPTION
*PreMenuOption
;
1447 Pos
= *CurrentPosition
;
1448 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1451 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1452 if (NextMenuOption
->Row
== 0) {
1453 UpdateOptionSkipLines (Selection
, NextMenuOption
);
1456 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1458 // Current Position doesn't need to be caculated when go up.
1459 // Caculate distanct at first when go up
1461 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1462 NextMenuOption
= PreMenuOption
;
1465 Distance
+= NextMenuOption
->Skip
;
1467 if (IsSelectable (NextMenuOption
)) {
1470 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1479 // Caculate distanct at later when go down
1481 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1482 NextMenuOption
= PreMenuOption
;
1485 Distance
+= NextMenuOption
->Skip
;
1487 PreMenuOption
= NextMenuOption
;
1488 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1491 *CurrentPosition
= &NextMenuOption
->Link
;
1497 Adjust Data and Time position accordingly.
1498 Data format : [01/02/2004] [11:22:33]
1499 Line number : 0 0 1 0 0 1
1501 This is an internal function.
1503 @param DirectionUp the up or down direction. False is down. True is
1505 @param CurrentPosition Current position. On return: Point to the last
1506 Option (Year or Second) if up; Point to the first
1507 Option (Month or Hour) if down.
1509 @return Return line number to pad. It is possible that we stand on a zero-advance
1510 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1514 AdjustDateAndTimePosition (
1515 IN BOOLEAN DirectionUp
,
1516 IN OUT LIST_ENTRY
**CurrentPosition
1520 LIST_ENTRY
*NewPosition
;
1521 UI_MENU_OPTION
*MenuOption
;
1522 UINTN PadLineNumber
;
1525 NewPosition
= *CurrentPosition
;
1526 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1528 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1529 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1531 // Calculate the distance from current position to the last Date/Time MenuOption
1534 while (MenuOption
->Skip
== 0) {
1536 NewPosition
= NewPosition
->ForwardLink
;
1537 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1541 NewPosition
= *CurrentPosition
;
1544 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1545 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1546 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1547 // checking can be done.
1549 while (Count
++ < 2) {
1550 NewPosition
= NewPosition
->BackLink
;
1554 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1555 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1556 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1557 // checking can be done.
1559 while (Count
-- > 0) {
1560 NewPosition
= NewPosition
->ForwardLink
;
1564 *CurrentPosition
= NewPosition
;
1567 return PadLineNumber
;
1571 Find HII Handle in the HII database associated with given Device Path.
1573 If DevicePath is NULL, then ASSERT.
1575 @param DevicePath Device Path associated with the HII package list
1578 @retval Handle HII package list Handle associated with the Device
1580 @retval NULL Hii Package list handle is not found.
1585 DevicePathToHiiHandle (
1586 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1590 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1595 EFI_HANDLE DriverHandle
;
1596 EFI_HII_HANDLE
*HiiHandles
;
1597 EFI_HII_HANDLE HiiHandle
;
1599 ASSERT (DevicePath
!= NULL
);
1601 TmpDevicePath
= DevicePath
;
1603 // Locate Device Path Protocol handle buffer
1605 Status
= gBS
->LocateDevicePath (
1606 &gEfiDevicePathProtocolGuid
,
1610 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1615 // Retrieve all HII Handles from HII database
1617 BufferSize
= 0x1000;
1618 HiiHandles
= AllocatePool (BufferSize
);
1619 ASSERT (HiiHandles
!= NULL
);
1620 Status
= mHiiDatabase
->ListPackageLists (
1622 EFI_HII_PACKAGE_TYPE_ALL
,
1627 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1628 FreePool (HiiHandles
);
1629 HiiHandles
= AllocatePool (BufferSize
);
1630 ASSERT (HiiHandles
!= NULL
);
1632 Status
= mHiiDatabase
->ListPackageLists (
1634 EFI_HII_PACKAGE_TYPE_ALL
,
1641 if (EFI_ERROR (Status
)) {
1642 FreePool (HiiHandles
);
1647 // Search Hii Handle by Driver Handle
1650 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1651 for (Index
= 0; Index
< HandleCount
; Index
++) {
1652 Status
= mHiiDatabase
->GetPackageListHandle (
1657 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1658 HiiHandle
= HiiHandles
[Index
];
1663 FreePool (HiiHandles
);
1668 Process the goto op code, update the info in the selection structure.
1670 @param Statement The statement belong to goto op code.
1671 @param Selection The selection info.
1672 @param Repaint Whether need to repaint the menu.
1673 @param NewLine Whether need to create new line.
1675 @retval EFI_SUCCESS The menu process successfully.
1676 @return Other value if the process failed.
1680 IN OUT FORM_BROWSER_STATEMENT
*Statement
,
1681 IN OUT UI_MENU_SELECTION
*Selection
,
1682 OUT BOOLEAN
*Repaint
,
1683 OUT BOOLEAN
*NewLine
1688 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1690 UINT8
*DevicePathBuffer
;
1693 FORM_BROWSER_FORM
*RefForm
;
1696 UI_MENU_LIST
*MenuList
;
1698 Status
= EFI_SUCCESS
;
1700 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0) {
1701 if (Selection
->Form
->ModalForm
) {
1705 // Goto another Hii Package list
1707 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1709 StringPtr
= GetToken (Statement
->HiiValue
.Value
.ref
.DevicePath
, Selection
->FormSet
->HiiHandle
);
1710 if (StringPtr
== NULL
) {
1712 // No device path string not found, exit
1714 Selection
->Action
= UI_ACTION_EXIT
;
1715 Selection
->Statement
= NULL
;
1718 BufferSize
= StrLen (StringPtr
) / 2;
1719 DevicePath
= AllocatePool (BufferSize
);
1720 ASSERT (DevicePath
!= NULL
);
1723 // Convert from Device Path String to DevicePath Buffer in the reverse order.
1725 DevicePathBuffer
= (UINT8
*) DevicePath
;
1726 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
1727 TemStr
[0] = StringPtr
[Index
];
1728 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
1729 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
1731 // Invalid Hex Char as the tail.
1735 if ((Index
& 1) == 0) {
1736 DevicePathBuffer
[Index
/2] = DigitUint8
;
1738 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
1742 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
1743 if (Selection
->Handle
== NULL
) {
1745 // If target Hii Handle not found, exit
1747 Selection
->Action
= UI_ACTION_EXIT
;
1748 Selection
->Statement
= NULL
;
1752 FreePool (StringPtr
);
1753 FreePool (DevicePath
);
1755 CopyMem (&Selection
->FormSetGuid
,&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1756 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1757 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1758 } else if (!CompareGuid (&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, &gZeroGuid
)) {
1759 if (Selection
->Form
->ModalForm
) {
1763 // Goto another Formset, check for uncommitted data
1765 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1767 CopyMem (&Selection
->FormSetGuid
, &Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1768 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1769 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1770 } else if (Statement
->HiiValue
.Value
.ref
.FormId
!= 0) {
1772 // Check whether target From is suppressed.
1774 RefForm
= IdToForm (Selection
->FormSet
, Statement
->HiiValue
.Value
.ref
.FormId
);
1776 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
1777 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
1778 if (EFI_ERROR (Status
)) {
1782 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
1784 // Form is suppressed.
1787 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
1788 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1789 if (Repaint
!= NULL
) {
1797 // Goto another form inside this formset,
1799 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1802 // Link current form so that we can always go back when someone hits the ESC
1804 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->HiiValue
.Value
.ref
.FormId
);
1805 if (MenuList
== NULL
&& Selection
->CurrentMenu
!= NULL
) {
1806 MenuList
= UiAddMenuList (Selection
->CurrentMenu
, &Selection
->FormSetGuid
, Statement
->HiiValue
.Value
.ref
.FormId
);
1809 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1810 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1811 } else if (Statement
->HiiValue
.Value
.ref
.QuestionId
!= 0) {
1813 // Goto another Question
1815 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1817 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1818 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1820 if (Repaint
!= NULL
) {
1823 if (NewLine
!= NULL
) {
1828 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
1829 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
1837 Display menu and wait for user to select one menu option, then return it.
1838 If AutoBoot is enabled, then if user doesn't select any option,
1839 after period of time, it will automatically return the first menu option.
1841 @param Selection Menu selection.
1843 @retval EFI_SUCESSS This function always return successfully for now.
1848 IN OUT UI_MENU_SELECTION
*Selection
1854 UINTN DistanceValue
;
1866 CHAR16
*OptionString
;
1867 CHAR16
*OutputString
;
1868 CHAR16
*FormattedString
;
1874 BOOLEAN InitializedFlag
;
1879 LIST_ENTRY
*TopOfScreen
;
1880 LIST_ENTRY
*SavedListEntry
;
1881 UI_MENU_OPTION
*MenuOption
;
1882 UI_MENU_OPTION
*NextMenuOption
;
1883 UI_MENU_OPTION
*SavedMenuOption
;
1884 UI_MENU_OPTION
*PreviousMenuOption
;
1885 UI_CONTROL_FLAG ControlFlag
;
1886 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1887 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1888 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
1889 UI_SCREEN_OPERATION ScreenOperation
;
1890 UINT8 MinRefreshInterval
;
1892 FORM_BROWSER_STATEMENT
*Statement
;
1893 UI_MENU_LIST
*CurrentMenu
;
1894 UINTN ModalSkipColumn
;
1895 BROWSER_HOT_KEY
*HotKey
;
1897 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1899 Status
= EFI_SUCCESS
;
1900 FormattedString
= NULL
;
1901 OptionString
= NULL
;
1902 ScreenOperation
= UiNoOperation
;
1904 MinRefreshInterval
= 0;
1907 OutputString
= NULL
;
1912 MenuRefreshEntry
= gMenuRefreshHead
;
1914 NextMenuOption
= NULL
;
1915 PreviousMenuOption
= NULL
;
1916 SavedMenuOption
= NULL
;
1918 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
1920 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1922 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1923 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1924 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1926 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1927 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1930 if (Selection
->Form
->ModalForm
) {
1931 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1933 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1936 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- gFooterHeight
- SCROLL_ARROW_HEIGHT
- 1;
1938 Selection
->TopRow
= TopRow
;
1939 Selection
->BottomRow
= BottomRow
;
1940 Selection
->PromptCol
= Col
;
1941 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1942 Selection
->Statement
= NULL
;
1944 TopOfScreen
= gMenuOption
.ForwardLink
;
1949 // Find current Menu
1951 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1952 if (CurrentMenu
== NULL
) {
1954 // Current menu not found, add it to the menu tree
1956 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1958 ASSERT (CurrentMenu
!= NULL
);
1959 Selection
->CurrentMenu
= CurrentMenu
;
1961 if (Selection
->QuestionId
== 0) {
1963 // Highlight not specified, fetch it from cached menu
1965 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1966 Selection
->Sequence
= CurrentMenu
->Sequence
;
1970 // Init option as the current user's selection
1972 InitializedFlag
= TRUE
;
1973 NewPos
= gMenuOption
.ForwardLink
;
1975 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1976 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1978 ControlFlag
= CfInitialization
;
1979 Selection
->Action
= UI_ACTION_NONE
;
1981 switch (ControlFlag
) {
1982 case CfInitialization
:
1983 if (IsListEmpty (&gMenuOption
)) {
1984 ControlFlag
= CfReadKey
;
1986 ControlFlag
= CfCheckSelection
;
1990 case CfCheckSelection
:
1991 if (Selection
->Action
!= UI_ACTION_NONE
) {
1992 ControlFlag
= CfExit
;
1994 ControlFlag
= CfRepaint
;
1999 ControlFlag
= CfRefreshHighLight
;
2009 Temp
= (UINTN
) SkipValue
;
2010 Temp2
= (UINTN
) SkipValue
;
2012 if (Selection
->Form
->ModalForm
) {
2014 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
2015 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
2016 TopRow
- SCROLL_ARROW_HEIGHT
,
2017 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2018 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2022 LocalScreen
.LeftColumn
,
2023 LocalScreen
.RightColumn
,
2024 TopRow
- SCROLL_ARROW_HEIGHT
,
2025 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2026 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2029 UiFreeRefreshList ();
2030 MinRefreshInterval
= 0;
2032 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2033 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2034 MenuOption
->Row
= Row
;
2035 MenuOption
->Col
= Col
;
2036 if (Selection
->Form
->ModalForm
) {
2037 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
2039 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2042 Statement
= MenuOption
->ThisTag
;
2043 if (Statement
->InSubtitle
) {
2044 MenuOption
->Col
+= SUBTITLE_INDENT
;
2047 if (MenuOption
->GrayOut
) {
2048 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2050 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2051 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2055 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2058 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
2060 // Print Arrow for Goto button.
2063 MenuOption
->Col
- 2,
2066 GEOMETRICSHAPE_RIGHT_TRIANGLE
2070 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2071 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2072 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
2075 // If there is more string to process print on the next row and increment the Skip value
2077 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2083 FreePool (OutputString
);
2092 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2093 if (EFI_ERROR (Status
)) {
2095 // Repaint to clear possible error prompt pop-up
2099 ControlFlag
= CfRepaint
;
2103 if (OptionString
!= NULL
) {
2104 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2106 // If leading spaces on OptionString - remove the spaces
2108 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
2109 MenuOption
->OptCol
++;
2112 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2113 OptionString
[Count
] = OptionString
[Index
];
2117 OptionString
[Count
] = CHAR_NULL
;
2120 Width
= (UINT16
) gOptionBlockWidth
;
2123 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2124 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2125 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2128 // If there is more string to process print on the next row and increment the Skip value
2130 if (StrLen (&OptionString
[Index
]) != 0) {
2134 // Since the Number of lines for this menu entry may or may not be reflected accurately
2135 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2136 // some testing to ensure we are keeping this in-sync.
2138 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2140 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2146 FreePool (OutputString
);
2155 FreePool (OptionString
);
2159 // If Question has refresh guid, register the op-code.
2161 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
2162 if (gMenuEventGuidRefreshHead
== NULL
) {
2163 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2164 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
2166 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
2167 while (MenuUpdateEntry
->Next
!= NULL
) {
2168 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2170 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2171 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2173 ASSERT (MenuUpdateEntry
!= NULL
);
2174 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
2175 ASSERT (!EFI_ERROR (Status
));
2176 MenuUpdateEntry
->MenuOption
= MenuOption
;
2177 MenuUpdateEntry
->Selection
= Selection
;
2178 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
2179 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
2180 if (MenuOption
->GrayOut
) {
2181 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2183 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2188 // If Question request refresh, register the op-code
2190 if (Statement
->RefreshInterval
!= 0) {
2192 // Menu will be refreshed at minimal interval of all Questions
2193 // which have refresh request
2195 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
2196 MinRefreshInterval
= Statement
->RefreshInterval
;
2199 if (gMenuRefreshHead
== NULL
) {
2200 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2201 gMenuRefreshHead
= MenuRefreshEntry
;
2203 MenuRefreshEntry
= gMenuRefreshHead
;
2204 while (MenuRefreshEntry
->Next
!= NULL
) {
2205 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2207 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2208 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2210 ASSERT (MenuRefreshEntry
!= NULL
);
2211 MenuRefreshEntry
->MenuOption
= MenuOption
;
2212 MenuRefreshEntry
->Selection
= Selection
;
2213 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2214 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2215 if (MenuOption
->GrayOut
) {
2216 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2218 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2223 // If this is a text op with secondary text information
2225 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2226 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2228 Width
= (UINT16
) gOptionBlockWidth
;
2231 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
2232 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2233 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2236 // If there is more string to process print on the next row and increment the Skip value
2238 if (StrLen (&StringPtr
[Index
]) != 0) {
2242 // Since the Number of lines for this menu entry may or may not be reflected accurately
2243 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2244 // some testing to ensure we are keeping this in-sync.
2246 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2248 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2254 FreePool (OutputString
);
2261 FreePool (StringPtr
);
2263 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2266 // Need to handle the bottom of the display
2268 if (MenuOption
->Skip
> 1) {
2269 Row
+= MenuOption
->Skip
- SkipValue
;
2272 Row
+= MenuOption
->Skip
;
2275 if (Row
> BottomRow
) {
2276 if (!ValueIsScroll (FALSE
, Link
)) {
2280 Row
= BottomRow
+ 1;
2285 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2290 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2292 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2293 TopRow
- SCROLL_ARROW_HEIGHT
,
2297 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2301 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2303 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2304 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2308 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2315 case CfRefreshHighLight
:
2317 // MenuOption: Last menu option that need to remove hilight
2318 // MenuOption is set to NULL in Repaint
2319 // NewPos: Current menu option that need to hilight
2321 ControlFlag
= CfUpdateHelpString
;
2322 if (InitializedFlag
) {
2323 InitializedFlag
= FALSE
;
2324 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
2328 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2329 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2331 SavedValue
= Repaint
;
2334 if (Selection
->QuestionId
!= 0) {
2335 NewPos
= gMenuOption
.ForwardLink
;
2336 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2338 while ((SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
||
2339 SavedMenuOption
->Sequence
!= Selection
->Sequence
) &&
2340 NewPos
->ForwardLink
!= &gMenuOption
) {
2341 NewPos
= NewPos
->ForwardLink
;
2342 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2344 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2346 // Target Question found, find its MenuOption
2350 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2351 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2352 Index
+= SavedMenuOption
->Skip
;
2353 if (Link
== TopOfScreen
) {
2354 Index
-= OldSkipValue
;
2356 Link
= Link
->ForwardLink
;
2358 if (NewPos
== Link
) {
2359 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2362 if (Link
!= NewPos
|| Index
> BottomRow
|| (Link
== NewPos
&& SavedMenuOption
->Row
+ SavedMenuOption
->Skip
- 1 > BottomRow
)) {
2364 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2366 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2368 // SavedMenuOption->Row == 0 means the menu not show yet.
2370 if (SavedMenuOption
->Row
== 0) {
2371 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2375 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= BottomRow
+ 1; ) {
2376 Link
= Link
->BackLink
;
2377 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2378 if (SavedMenuOption
->Row
== 0) {
2379 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2381 Index
+= SavedMenuOption
->Skip
;
2384 SkipValue
= Index
- BottomRow
- 1;
2385 if (SkipValue
> 0 && SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
2387 OldSkipValue
= SkipValue
;
2390 TopOfScreen
= Link
->ForwardLink
;
2395 ControlFlag
= CfRepaint
;
2400 // Target Question not found, highlight the default menu option
2402 NewPos
= TopOfScreen
;
2405 Selection
->QuestionId
= 0;
2408 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2409 if (MenuOption
!= NULL
) {
2411 // Remove highlight on last Menu Option
2413 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2414 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2415 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2416 if (OptionString
!= NULL
) {
2417 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2418 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2421 // If leading spaces on OptionString - remove the spaces
2423 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2426 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2427 OptionString
[Count
] = OptionString
[Index
];
2431 OptionString
[Count
] = CHAR_NULL
;
2434 Width
= (UINT16
) gOptionBlockWidth
;
2435 OriginalRow
= MenuOption
->Row
;
2437 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2438 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2439 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2442 // If there is more string to process print on the next row and increment the Skip value
2444 if (StrLen (&OptionString
[Index
]) != 0) {
2448 FreePool (OutputString
);
2451 MenuOption
->Row
= OriginalRow
;
2453 FreePool (OptionString
);
2456 if (MenuOption
->GrayOut
) {
2457 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2458 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2459 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2462 OriginalRow
= MenuOption
->Row
;
2463 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2465 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2466 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2467 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2470 // If there is more string to process print on the next row and increment the Skip value
2472 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2476 FreePool (OutputString
);
2479 MenuOption
->Row
= OriginalRow
;
2480 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2486 // This is the current selected statement
2488 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2489 Statement
= MenuOption
->ThisTag
;
2490 Selection
->Statement
= Statement
;
2491 if (!IsSelectable (MenuOption
)) {
2492 Repaint
= SavedValue
;
2493 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2498 // Record highlight for current menu
2500 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2501 CurrentMenu
->Sequence
= MenuOption
->Sequence
;
2504 // Set reverse attribute
2506 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2507 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2510 // Assuming that we have a refresh linked-list created, lets annotate the
2511 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2512 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2514 if (gMenuRefreshHead
!= NULL
) {
2515 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2516 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2517 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2519 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2521 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2522 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2527 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2528 if (OptionString
!= NULL
) {
2529 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2531 // If leading spaces on OptionString - remove the spaces
2533 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2536 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2537 OptionString
[Count
] = OptionString
[Index
];
2541 OptionString
[Count
] = CHAR_NULL
;
2543 Width
= (UINT16
) gOptionBlockWidth
;
2545 OriginalRow
= MenuOption
->Row
;
2547 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2548 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2549 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2552 // If there is more string to process print on the next row and increment the Skip value
2554 if (StrLen (&OptionString
[Index
]) != 0) {
2558 FreePool (OutputString
);
2561 MenuOption
->Row
= OriginalRow
;
2563 FreePool (OptionString
);
2566 OriginalRow
= MenuOption
->Row
;
2568 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2570 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2571 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2572 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2575 // If there is more string to process print on the next row and increment the Skip value
2577 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2581 FreePool (OutputString
);
2584 MenuOption
->Row
= OriginalRow
;
2589 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2592 // Clear reverse attribute
2594 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2597 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2598 // if we didn't break halfway when process CfRefreshHighLight.
2600 Repaint
= SavedValue
;
2603 case CfUpdateHelpString
:
2604 ControlFlag
= CfPrepareToReadKey
;
2605 if (Selection
->Form
->ModalForm
) {
2609 if (Repaint
|| NewLine
) {
2611 // Don't print anything if it is a NULL help token
2613 ASSERT(MenuOption
!= NULL
);
2614 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2617 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2620 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2622 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2624 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2626 // Pad String with spaces to simulate a clearing of the previous line
2628 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2629 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2633 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2635 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2640 // Reset this flag every time we finish using it.
2646 case CfPrepareToReadKey
:
2647 ControlFlag
= CfReadKey
;
2648 ScreenOperation
= UiNoOperation
;
2652 ControlFlag
= CfScreenOperation
;
2655 // Wait for user's selection
2658 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2659 } while (Status
== EFI_TIMEOUT
);
2661 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2663 // IFR is updated in Callback of refresh opcode, re-parse it
2665 ControlFlag
= CfCheckSelection
;
2666 Selection
->Statement
= NULL
;
2670 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2672 // If we encounter error, continue to read another key in.
2674 if (EFI_ERROR (Status
)) {
2675 ControlFlag
= CfReadKey
;
2679 switch (Key
.UnicodeChar
) {
2680 case CHAR_CARRIAGE_RETURN
:
2681 ScreenOperation
= UiSelect
;
2686 // We will push the adjustment of these numeric values directly to the input handler
2687 // NOTE: we won't handle manual input numeric
2692 // If the screen has no menu items, and the user didn't select UiReset
2693 // ignore the selection and go back to reading keys.
2695 if(IsListEmpty (&gMenuOption
)) {
2696 ControlFlag
= CfReadKey
;
2700 ASSERT(MenuOption
!= NULL
);
2701 Statement
= MenuOption
->ThisTag
;
2702 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2703 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2704 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2706 if (Key
.UnicodeChar
== '+') {
2707 gDirection
= SCAN_RIGHT
;
2709 gDirection
= SCAN_LEFT
;
2711 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2712 if (EFI_ERROR (Status
)) {
2714 // Repaint to clear possible error prompt pop-up
2719 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2721 if (OptionString
!= NULL
) {
2722 FreePool (OptionString
);
2728 ScreenOperation
= UiUp
;
2733 ScreenOperation
= UiDown
;
2737 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2739 // If the screen has no menu items, and the user didn't select UiReset
2740 // ignore the selection and go back to reading keys.
2742 if(IsListEmpty (&gMenuOption
)) {
2743 ControlFlag
= CfReadKey
;
2747 ASSERT(MenuOption
!= NULL
);
2748 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2749 ScreenOperation
= UiSelect
;
2755 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2756 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2757 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2762 if (Selection
->Form
->ModalForm
&& (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2764 // ModalForm has no ESC key and Hot Key.
2766 ControlFlag
= CfReadKey
;
2767 } else if (Index
== mScanCodeNumber
) {
2769 // Check whether Key matches the registered hot key.
2772 if ((gBrowserSettingScope
== SystemLevel
) || (gFunctionKeySetting
!= NONE_FUNCTION_KEY_SETTING
)) {
2773 HotKey
= GetHotKeyFromRegisterList (&Key
);
2775 if (HotKey
!= NULL
) {
2776 ScreenOperation
= UiHotKey
;
2783 case CfScreenOperation
:
2784 if (ScreenOperation
!= UiReset
) {
2786 // If the screen has no menu items, and the user didn't select UiReset
2787 // ignore the selection and go back to reading keys.
2789 if (IsListEmpty (&gMenuOption
)) {
2790 ControlFlag
= CfReadKey
;
2796 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2799 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2800 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2807 ControlFlag
= CfCheckSelection
;
2809 ASSERT(MenuOption
!= NULL
);
2810 Statement
= MenuOption
->ThisTag
;
2811 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2816 // Keep highlight on current MenuOption
2818 Selection
->QuestionId
= Statement
->QuestionId
;
2820 switch (Statement
->Operand
) {
2821 case EFI_IFR_REF_OP
:
2822 ProcessGotoOpCode(Statement
, Selection
, &Repaint
, &NewLine
);
2825 case EFI_IFR_ACTION_OP
:
2827 // Process the Config string <ConfigResp>
2829 Status
= ProcessQuestionConfig (Selection
, Statement
);
2831 if (EFI_ERROR (Status
)) {
2836 // The action button may change some Question value, so refresh the form
2838 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2841 case EFI_IFR_RESET_BUTTON_OP
:
2843 // Reset Question to default value specified by DefaultId
2845 ControlFlag
= CfUiDefault
;
2846 DefaultId
= Statement
->DefaultId
;
2851 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2853 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2854 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2856 if (EFI_ERROR (Status
)) {
2859 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2861 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2864 if (OptionString
!= NULL
) {
2865 FreePool (OptionString
);
2873 // We come here when someone press ESC
2875 ControlFlag
= CfCheckSelection
;
2876 FindNextMenu (Selection
, &Repaint
, &NewLine
);
2880 ControlFlag
= CfCheckSelection
;
2881 ASSERT(MenuOption
!= NULL
);
2882 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2883 if (MenuOption
->Sequence
!= 0) {
2885 // In the middle or tail of the Date/Time op-code set, go left.
2887 ASSERT(NewPos
!= NULL
);
2888 NewPos
= NewPos
->BackLink
;
2894 ControlFlag
= CfCheckSelection
;
2895 ASSERT(MenuOption
!= NULL
);
2896 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2897 if (MenuOption
->Sequence
!= 2) {
2899 // In the middle or tail of the Date/Time op-code set, go left.
2901 ASSERT(NewPos
!= NULL
);
2902 NewPos
= NewPos
->ForwardLink
;
2908 ControlFlag
= CfCheckSelection
;
2910 SavedListEntry
= NewPos
;
2912 ASSERT(NewPos
!= NULL
);
2914 // Adjust Date/Time position before we advance forward.
2916 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2917 if (NewPos
->BackLink
!= &gMenuOption
) {
2918 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2919 ASSERT (MenuOption
!= NULL
);
2921 NewPos
= NewPos
->BackLink
;
2923 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2924 if (PreviousMenuOption
->Row
== 0) {
2925 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
2927 DistanceValue
= PreviousMenuOption
->Skip
;
2929 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2930 Difference
= MoveToNextStatement (Selection
, TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2932 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2934 if (Difference
< 0) {
2936 // We hit the begining MenuOption that can be focused
2937 // so we simply scroll to the top.
2939 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2940 TopOfScreen
= gMenuOption
.ForwardLink
;
2944 // Scroll up to the last page when we have arrived at top page.
2946 NewPos
= &gMenuOption
;
2947 TopOfScreen
= &gMenuOption
;
2948 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2949 ScreenOperation
= UiPageUp
;
2950 ControlFlag
= CfScreenOperation
;
2953 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2955 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2957 TopOfScreen
= NewPos
;
2961 } else if (!IsSelectable (NextMenuOption
)) {
2963 // Continue to go up until scroll to next page or the selectable option is found.
2965 ScreenOperation
= UiUp
;
2966 ControlFlag
= CfScreenOperation
;
2970 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2972 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2973 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2974 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2975 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2978 // Scroll up to the last page.
2980 NewPos
= &gMenuOption
;
2981 TopOfScreen
= &gMenuOption
;
2982 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2983 ScreenOperation
= UiPageUp
;
2984 ControlFlag
= CfScreenOperation
;
2989 ControlFlag
= CfCheckSelection
;
2991 ASSERT(NewPos
!= NULL
);
2992 if (NewPos
->BackLink
== &gMenuOption
) {
3002 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
3003 Link
= Link
->BackLink
;
3004 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3005 if (PreviousMenuOption
->Row
== 0) {
3006 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3008 if (Index
< PreviousMenuOption
->Skip
) {
3012 Index
= Index
- PreviousMenuOption
->Skip
;
3015 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
3016 if (TopOfScreen
== &gMenuOption
) {
3017 TopOfScreen
= gMenuOption
.ForwardLink
;
3018 NewPos
= gMenuOption
.BackLink
;
3019 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3021 } else if (TopOfScreen
!= Link
) {
3024 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3027 // Finally we know that NewPos is the last MenuOption can be focused.
3031 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3034 if (Index
+ 1 < TopRow
) {
3036 // Back up the previous option.
3038 Link
= Link
->ForwardLink
;
3042 // Move to the option in Next page.
3044 if (TopOfScreen
== &gMenuOption
) {
3045 NewPos
= gMenuOption
.BackLink
;
3046 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3049 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3053 // There are more MenuOption needing scrolling up.
3060 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3061 // Don't do this when we are already in the first page.
3063 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3064 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3068 ControlFlag
= CfCheckSelection
;
3070 ASSERT (NewPos
!= NULL
);
3071 if (NewPos
->ForwardLink
== &gMenuOption
) {
3080 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3082 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
3083 Index
= Index
+ NextMenuOption
->Skip
;
3084 Link
= Link
->ForwardLink
;
3085 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3088 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
3090 // Finally we know that NewPos is the last MenuOption can be focused.
3093 MoveToNextStatement (Selection
, TRUE
, &Link
, Index
- TopRow
);
3095 if (Index
- 1 > BottomRow
) {
3097 // Back up the previous option.
3099 Link
= Link
->BackLink
;
3102 // There are more MenuOption needing scrolling down.
3107 // Move to the option in Next page.
3109 MoveToNextStatement (Selection
, FALSE
, &Link
, BottomRow
- TopRow
);
3113 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3114 // Don't do this when we are already in the last page.
3117 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3118 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3122 ControlFlag
= CfCheckSelection
;
3124 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3125 // to be one that progresses to the next set of op-codes, we need to advance to the last
3126 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3127 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3128 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3129 // the Date/Time op-code.
3131 SavedListEntry
= NewPos
;
3132 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3134 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3135 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3137 NewPos
= NewPos
->ForwardLink
;
3140 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3141 Difference
= MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3143 // We hit the end of MenuOption that can be focused
3144 // so we simply scroll to the first page.
3146 if (Difference
< 0) {
3148 // Scroll to the first page.
3150 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3151 TopOfScreen
= gMenuOption
.ForwardLink
;
3155 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3157 NewPos
= gMenuOption
.ForwardLink
;
3158 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3161 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3163 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3164 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3168 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3171 // An option might be multi-line, so we need to reflect that data in the overall skip value
3173 UpdateOptionSkipLines (Selection
, NextMenuOption
);
3174 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3176 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3177 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3178 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3179 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3185 // If we are going to scroll, update TopOfScreen
3187 if (Temp
> BottomRow
) {
3190 // Is the current top of screen a zero-advance op-code?
3191 // If so, keep moving forward till we hit a >0 advance op-code
3193 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3196 // If bottom op-code is more than one line or top op-code is more than one line
3198 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3200 // Is the bottom op-code greater than or equal in size to the top op-code?
3202 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3204 // Skip the top op-code
3206 TopOfScreen
= TopOfScreen
->ForwardLink
;
3207 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3209 OldSkipValue
= Difference
;
3211 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3214 // If we have a remainder, skip that many more op-codes until we drain the remainder
3216 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3218 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3220 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3221 TopOfScreen
= TopOfScreen
->ForwardLink
;
3222 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3225 // Since we will act on this op-code in the next routine, and increment the
3226 // SkipValue, set the skips to one less than what is required.
3228 SkipValue
= Difference
- 1;
3232 // Since we will act on this op-code in the next routine, and increment the
3233 // SkipValue, set the skips to one less than what is required.
3235 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3238 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3239 TopOfScreen
= TopOfScreen
->ForwardLink
;
3242 SkipValue
= OldSkipValue
;
3246 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3247 // Let's set a skip flag to smoothly scroll the top of the screen.
3249 if (SavedMenuOption
->Skip
> 1) {
3250 if (SavedMenuOption
== NextMenuOption
) {
3255 } else if (SavedMenuOption
->Skip
== 1) {
3259 TopOfScreen
= TopOfScreen
->ForwardLink
;
3261 } while (SavedMenuOption
->Skip
== 0);
3264 OldSkipValue
= SkipValue
;
3265 } else if (!IsSelectable (NextMenuOption
)) {
3267 // Continue to go down until scroll to next page or the selectable option is found.
3269 ScreenOperation
= UiDown
;
3270 ControlFlag
= CfScreenOperation
;
3273 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3275 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3279 // Scroll to the first page.
3281 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3282 TopOfScreen
= gMenuOption
.ForwardLink
;
3286 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3289 NewPos
= gMenuOption
.ForwardLink
;
3290 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3294 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3296 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3297 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3301 ControlFlag
= CfCheckSelection
;
3303 Status
= EFI_SUCCESS
;
3305 // Discard changes. After it, no NV flag is showed.
3307 if ((HotKey
->Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
3308 Status
= DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3309 if (!EFI_ERROR (Status
)) {
3310 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3311 Selection
->Statement
= NULL
;
3312 gResetRequired
= FALSE
;
3315 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDiscardFailed
, gPressEnter
, gEmptyString
);
3316 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3318 // Still show current page.
3320 Selection
->Action
= UI_ACTION_NONE
;
3328 // Reterieve default setting. After it. NV flag will be showed.
3330 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3331 Status
= ExtractDefault (Selection
->FormSet
, Selection
->Form
, HotKey
->DefaultId
, gBrowserSettingScope
);
3332 if (!EFI_ERROR (Status
)) {
3333 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3334 Selection
->Statement
= NULL
;
3335 gResetRequired
= TRUE
;
3338 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDefaultFailed
, gPressEnter
, gEmptyString
);
3339 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3341 // Still show current page.
3343 Selection
->Action
= UI_ACTION_NONE
;
3351 // Save changes. After it, no NV flag is showed.
3353 if ((HotKey
->Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
3354 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3355 if (!EFI_ERROR (Status
)) {
3356 ASSERT(MenuOption
!= NULL
);
3357 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3358 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3361 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3362 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3364 // Still show current page.
3366 Selection
->Action
= UI_ACTION_NONE
;
3374 // Set Reset required Flag
3376 if ((HotKey
->Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
3377 gResetRequired
= TRUE
;
3383 if ((HotKey
->Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
3385 // Form Exit without saving, Similar to ESC Key.
3386 // FormSet Exit without saving, Exit SendForm.
3387 // System Exit without saving, CallExitHandler and Exit SendForm.
3389 DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3390 if (gBrowserSettingScope
== FormLevel
) {
3391 ControlFlag
= CfUiReset
;
3392 } else if (gBrowserSettingScope
== FormSetLevel
) {
3393 Selection
->Action
= UI_ACTION_EXIT
;
3394 } else if (gBrowserSettingScope
== SystemLevel
) {
3395 if (ExitHandlerFunction
!= NULL
) {
3396 ExitHandlerFunction ();
3398 Selection
->Action
= UI_ACTION_EXIT
;
3400 Selection
->Statement
= NULL
;
3405 ControlFlag
= CfCheckSelection
;
3407 // Reset to default value for all forms in the whole system.
3409 Status
= ExtractDefault (Selection
->FormSet
, NULL
, DefaultId
, FormSetLevel
);
3411 if (!EFI_ERROR (Status
)) {
3412 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3413 Selection
->Statement
= NULL
;
3414 gResetRequired
= TRUE
;
3418 case CfUiNoOperation
:
3419 ControlFlag
= CfCheckSelection
;
3423 UiFreeRefreshList ();
3425 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3426 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3427 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3428 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");