2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 LIST_ENTRY gMenuOption
;
18 LIST_ENTRY gMenuList
= INITIALIZE_LIST_HEAD_VARIABLE (gMenuList
);
19 MENU_REFRESH_ENTRY
*gMenuRefreshHead
; // Menu list used for refresh timer opcode.
20 MENU_REFRESH_ENTRY
*gMenuEventGuidRefreshHead
; // Menu list used for refresh event guid opcode.
23 // Search table for UiDisplayMenu()
25 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
56 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
58 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
102 BOOLEAN GetLineByWidthFinished
= FALSE
;
106 Set Buffer to Value for Size bytes.
108 @param Buffer Memory to set.
109 @param Size Number of bytes to set
110 @param Value Value of the set operation.
123 while ((Size
--) != 0) {
130 Initialize Menu option list.
138 InitializeListHead (&gMenuOption
);
143 Free Menu option linked list.
151 UI_MENU_OPTION
*MenuOption
;
153 while (!IsListEmpty (&gMenuOption
)) {
154 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
155 RemoveEntryList (&MenuOption
->Link
);
158 // We allocated space for this description when we did a GetToken, free it here
160 if (MenuOption
->Skip
!= 0) {
162 // For date/time, MenuOption->Description is shared by three Menu Options
163 // Data format : [01/02/2004] [11:22:33]
164 // Line number : 0 0 1 0 0 1
166 FreePool (MenuOption
->Description
);
168 FreePool (MenuOption
);
174 Create a menu with specified formset GUID and form ID, and add it as a child
175 of the given parent menu.
177 @param Parent The parent of menu to be added.
178 @param HiiHandle Hii handle related to this formset.
179 @param FormSetGuid The Formset Guid of menu to be added.
180 @param FormId The Form ID of menu to be added.
182 @return A pointer to the newly added menu or NULL if memory is insufficient.
187 IN OUT UI_MENU_LIST
*Parent
,
188 IN EFI_HII_HANDLE HiiHandle
,
189 IN EFI_GUID
*FormSetGuid
,
193 UI_MENU_LIST
*MenuList
;
195 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
196 if (MenuList
== NULL
) {
200 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
201 InitializeListHead (&MenuList
->ChildListHead
);
203 MenuList
->HiiHandle
= HiiHandle
;
204 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
205 MenuList
->FormId
= FormId
;
206 MenuList
->Parent
= Parent
;
208 if (Parent
== NULL
) {
210 // If parent is not specified, it is the root Form of a Formset
212 InsertTailList (&gMenuList
, &MenuList
->Link
);
214 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
222 Search Menu with given FormId and FormSetGuid in all cached menu list.
224 @param Parent The parent of menu to search.
225 @param FormSetGuid The Formset GUID of the menu to search.
226 @param FormId The Form ID of menu to search.
228 @return A pointer to menu found or NULL if not found.
232 UiFindChildMenuList (
233 IN UI_MENU_LIST
*Parent
,
234 IN EFI_GUID
*FormSetGuid
,
240 UI_MENU_LIST
*MenuList
;
242 ASSERT (Parent
!= NULL
);
244 if (Parent
->FormId
== FormId
&& CompareGuid (FormSetGuid
, &Parent
->FormSetGuid
)) {
248 Link
= GetFirstNode (&Parent
->ChildListHead
);
249 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
250 Child
= UI_MENU_LIST_FROM_LINK (Link
);
252 MenuList
= UiFindChildMenuList (Child
, FormSetGuid
, FormId
);
253 if (MenuList
!= NULL
) {
257 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
265 Search Menu with given FormSetGuid and FormId in all cached menu list.
267 @param FormSetGuid The Formset GUID of the menu to search.
268 @param FormId The Form ID of menu to search.
270 @return A pointer to menu found or NULL if not found.
275 IN EFI_GUID
*FormSetGuid
,
280 UI_MENU_LIST
*MenuList
;
283 Link
= GetFirstNode (&gMenuList
);
284 while (!IsNull (&gMenuList
, Link
)) {
285 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
287 Child
= UiFindChildMenuList(MenuList
, FormSetGuid
, FormId
);
292 Link
= GetNextNode (&gMenuList
, Link
);
300 Free Menu option linked list.
308 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
310 while (gMenuRefreshHead
!= NULL
) {
311 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
312 FreePool (gMenuRefreshHead
);
313 gMenuRefreshHead
= OldMenuRefreshEntry
;
316 while (gMenuEventGuidRefreshHead
!= NULL
) {
317 OldMenuRefreshEntry
= gMenuEventGuidRefreshHead
->Next
;
318 if (gMenuEventGuidRefreshHead
!= NULL
) {
319 gBS
->CloseEvent(gMenuEventGuidRefreshHead
->Event
);
321 FreePool (gMenuEventGuidRefreshHead
);
322 gMenuEventGuidRefreshHead
= OldMenuRefreshEntry
;
328 Process option string for date/time opcode.
330 @param MenuOption Menu option point to date/time.
331 @param OptionString Option string input for process.
332 @param AddOptCol Whether need to update MenuOption->OptCol.
336 ProcessStringForDateTime (
337 UI_MENU_OPTION
*MenuOption
,
338 CHAR16
*OptionString
,
344 FORM_BROWSER_STATEMENT
*Statement
;
346 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
348 Statement
= MenuOption
->ThisTag
;
351 // If leading spaces on OptionString - remove the spaces
353 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
355 // Base on the blockspace to get the option column info.
358 MenuOption
->OptCol
++;
362 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
363 OptionString
[Count
] = OptionString
[Index
];
366 OptionString
[Count
] = CHAR_NULL
;
369 // Enable to suppress field in the opcode base on the flag.
371 if (Statement
->Operand
== EFI_IFR_DATE_OP
) {
373 // OptionString format is: <**: **: ****>
377 if ((Statement
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
379 // At this point, only "<**:" in the optionstring.
380 // Clean the day's ** field, after clean, the format is "< :"
382 SetUnicodeMem (&OptionString
[1], 2, L
' ');
383 } else if ((Statement
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
385 // At this point, only "**:" in the optionstring.
386 // Clean the month's "**" field, after clean, the format is " :"
388 SetUnicodeMem (&OptionString
[0], 2, L
' ');
389 } else if ((Statement
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
391 // At this point, only "****>" in the optionstring.
392 // Clean the year's "****" field, after clean, the format is " >"
394 SetUnicodeMem (&OptionString
[0], 4, L
' ');
396 } else if (Statement
->Operand
== EFI_IFR_TIME_OP
) {
398 // OptionString format is: <**: **: **>
399 // |hour|minute|second|
402 if ((Statement
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
404 // At this point, only "<**:" in the optionstring.
405 // Clean the hour's ** field, after clean, the format is "< :"
407 SetUnicodeMem (&OptionString
[1], 2, L
' ');
408 } else if ((Statement
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
410 // At this point, only "**:" in the optionstring.
411 // Clean the minute's "**" field, after clean, the format is " :"
413 SetUnicodeMem (&OptionString
[0], 2, L
' ');
414 } else if ((Statement
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
416 // At this point, only "**>" in the optionstring.
417 // Clean the second's "**" field, after clean, the format is " >"
419 SetUnicodeMem (&OptionString
[0], 2, L
' ');
427 @param MenuRefreshEntry Menu refresh structure which has info about the refresh question.
431 IN MENU_REFRESH_ENTRY
*MenuRefreshEntry
434 CHAR16
*OptionString
;
436 UI_MENU_SELECTION
*Selection
;
437 FORM_BROWSER_STATEMENT
*Question
;
439 Selection
= MenuRefreshEntry
->Selection
;
440 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
442 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, GetSetValueWithHiiDriver
);
443 if (EFI_ERROR (Status
)) {
448 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
450 if (OptionString
!= NULL
) {
452 // If old Text is longer than new string, need to clean the old string before paint the newer.
453 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
455 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
456 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
458 MenuRefreshEntry
->CurrentColumn
,
459 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
460 MenuRefreshEntry
->CurrentRow
,
461 MenuRefreshEntry
->CurrentRow
,
462 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
466 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
467 ProcessStringForDateTime(MenuRefreshEntry
->MenuOption
, OptionString
, FALSE
);
468 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, OptionString
);
469 FreePool (OptionString
);
473 // Question value may be changed, need invoke its Callback()
475 Status
= ProcessCallBackFunction (Selection
, Question
, EFI_BROWSER_ACTION_CHANGING
, FALSE
);
481 Refresh the question which has refresh guid event attribute.
483 @param Event The event which has this function related.
484 @param Context The input context info related to this event or the status code return to the caller.
488 RefreshQuestionNotify(
493 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
494 UI_MENU_SELECTION
*Selection
;
497 // Reset FormPackage update flag
499 mHiiPackageListUpdated
= FALSE
;
501 MenuRefreshEntry
= (MENU_REFRESH_ENTRY
*)Context
;
502 ASSERT (MenuRefreshEntry
!= NULL
);
503 Selection
= MenuRefreshEntry
->Selection
;
505 RefreshQuestion (MenuRefreshEntry
);
507 if (mHiiPackageListUpdated
) {
509 // Package list is updated, force to reparse IFR binary of target Formset
511 mHiiPackageListUpdated
= FALSE
;
512 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
526 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
528 UI_MENU_SELECTION
*Selection
;
530 if (gMenuRefreshHead
!= NULL
) {
532 // call from refresh interval process.
534 MenuRefreshEntry
= gMenuRefreshHead
;
535 Selection
= MenuRefreshEntry
->Selection
;
537 // Reset FormPackage update flag
539 mHiiPackageListUpdated
= FALSE
;
542 Status
= RefreshQuestion (MenuRefreshEntry
);
543 if (EFI_ERROR (Status
)) {
547 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
549 } while (MenuRefreshEntry
!= NULL
);
551 if (mHiiPackageListUpdated
) {
553 // Package list is updated, force to reparse IFR binary of target Formset
555 mHiiPackageListUpdated
= FALSE
;
556 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
566 Wait for a given event to fire, or for an optional timeout to expire.
568 @param Event The event to wait for
569 @param Timeout An optional timeout value in 100 ns units.
570 @param RefreshInterval Menu refresh interval (in seconds).
572 @retval EFI_SUCCESS Event fired before Timeout expired.
573 @retval EFI_TIME_OUT Timout expired before Event fired.
577 UiWaitForSingleEvent (
579 IN UINT64 Timeout
, OPTIONAL
580 IN UINT8 RefreshInterval OPTIONAL
585 EFI_EVENT TimerEvent
;
586 EFI_EVENT WaitList
[2];
590 // Create a timer event
592 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
593 if (!EFI_ERROR (Status
)) {
595 // Set the timer event
604 // Wait for the original event or the timer
607 WaitList
[1] = TimerEvent
;
608 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
609 gBS
->CloseEvent (TimerEvent
);
612 // If the timer expired, change the return to timed out
614 if (!EFI_ERROR (Status
) && Index
== 1) {
615 Status
= EFI_TIMEOUT
;
620 // Update screen every second
622 if (RefreshInterval
== 0) {
623 Timeout
= ONE_SECOND
;
625 Timeout
= RefreshInterval
* ONE_SECOND
;
629 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
632 // Set the timer event
641 // Wait for the original event or the timer
644 WaitList
[1] = TimerEvent
;
645 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
648 // If the timer expired, update anything that needs a refresh and keep waiting
650 if (!EFI_ERROR (Status
) && Index
== 1) {
651 Status
= EFI_TIMEOUT
;
652 if (RefreshInterval
!= 0) {
653 Status
= RefreshForm ();
657 gBS
->CloseEvent (TimerEvent
);
658 } while (Status
== EFI_TIMEOUT
);
666 Add one menu option by specified description and context.
668 @param String String description for this option.
669 @param Handle Hii handle for the package list.
670 @param Form The form this statement belong to.
671 @param Statement Statement of this Menu Option.
672 @param NumberOfLines Display lines for this Menu Option.
673 @param MenuItemCount The index for this Option in the Menu.
675 @retval Pointer Pointer to the added Menu Option.
681 IN EFI_HII_HANDLE Handle
,
682 IN FORM_BROWSER_FORM
*Form
,
683 IN FORM_BROWSER_STATEMENT
*Statement
,
684 IN UINT16 NumberOfLines
,
685 IN UINT16 MenuItemCount
688 UI_MENU_OPTION
*MenuOption
;
695 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
697 // Add three MenuOptions for Date/Time
698 // Data format : [01/02/2004] [11:22:33]
699 // Line number : 0 0 1 0 0 1
704 if (Statement
->Storage
== NULL
) {
706 // For RTC type of date/time, set default refresh interval to be 1 second
708 if (Statement
->RefreshInterval
== 0) {
709 Statement
->RefreshInterval
= 1;
714 for (Index
= 0; Index
< Count
; Index
++) {
715 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
718 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
719 MenuOption
->Description
= String
;
720 MenuOption
->Handle
= Handle
;
721 MenuOption
->ThisTag
= Statement
;
722 MenuOption
->EntryNumber
= MenuItemCount
;
726 // Override LineNumber for the MenuOption in Date/Time sequence
728 MenuOption
->Skip
= 1;
730 MenuOption
->Skip
= NumberOfLines
;
732 MenuOption
->Sequence
= Index
;
734 if (EvaluateExpressionList(Statement
->Expression
, FALSE
, NULL
, NULL
) == ExpressGrayOut
) {
735 MenuOption
->GrayOut
= TRUE
;
737 MenuOption
->GrayOut
= FALSE
;
741 // If the form or the question has the lock attribute, deal same as grayout.
743 if (Form
->Locked
|| Statement
->Locked
) {
744 MenuOption
->GrayOut
= TRUE
;
747 switch (Statement
->Operand
) {
748 case EFI_IFR_ORDERED_LIST_OP
:
749 case EFI_IFR_ONE_OF_OP
:
750 case EFI_IFR_NUMERIC_OP
:
751 case EFI_IFR_TIME_OP
:
752 case EFI_IFR_DATE_OP
:
753 case EFI_IFR_CHECKBOX_OP
:
754 case EFI_IFR_PASSWORD_OP
:
755 case EFI_IFR_STRING_OP
:
757 // User could change the value of these items
759 MenuOption
->IsQuestion
= TRUE
;
762 case EFI_IFR_TEXT_OP
:
763 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
765 // Initializing GrayOut option as TRUE for Text setup options
766 // so that those options will be Gray in colour and un selectable.
768 MenuOption
->GrayOut
= TRUE
;
771 // break skipped on purpose
774 MenuOption
->IsQuestion
= FALSE
;
778 if ((Statement
->ValueExpression
!= NULL
) ||
779 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
780 MenuOption
->ReadOnly
= TRUE
;
783 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
791 Routine used to abstract a generic dialog interface and return the selected key or string
793 @param NumberOfLines The number of lines for the dialog box
794 @param HotKey Defines whether a single character is parsed
795 (TRUE) and returned in KeyValue or a string is
796 returned in StringBuffer. Two special characters
797 are considered when entering a string, a SCAN_ESC
798 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
799 string input and returns
800 @param MaximumStringSize The maximum size in bytes of a typed in string
801 (each character is a CHAR16) and the minimum
802 string returned is two bytes
803 @param StringBuffer The passed in pointer to the buffer which will
804 hold the typed in string if HotKey is FALSE
805 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
806 @param ... A series of (quantity == NumberOfLines) text
807 strings which will be used to construct the dialog
810 @retval EFI_SUCCESS Displayed dialog and received user interaction
811 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
812 (StringBuffer == NULL) && (HotKey == FALSE))
813 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
819 IN UINTN NumberOfLines
,
821 IN UINTN MaximumStringSize
,
822 OUT CHAR16
*StringBuffer
,
823 OUT EFI_INPUT_KEY
*KeyValue
,
832 CHAR16
*BufferedString
;
839 BOOLEAN SelectionComplete
;
841 UINTN CurrentAttribute
;
842 UINTN DimensionsWidth
;
843 UINTN DimensionsHeight
;
845 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
846 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
848 SelectionComplete
= FALSE
;
850 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
851 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
852 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
855 ASSERT (BufferedString
);
858 // Zero the outgoing buffer
860 ZeroMem (StringBuffer
, MaximumStringSize
);
863 if (KeyValue
== NULL
) {
864 return EFI_INVALID_PARAMETER
;
867 if (StringBuffer
== NULL
) {
868 return EFI_INVALID_PARAMETER
;
874 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
878 VA_START (Marker
, KeyValue
);
881 // Determine the largest string in the dialog box
882 // Notice we are starting with 1 since String is the first string
884 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
885 StackString
= VA_ARG (Marker
, CHAR16
*);
887 if (StackString
[0] == L
' ') {
888 InputOffset
= Count
+ 1;
891 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
893 // Size of the string visually and subtract the width by one for the null-terminator
895 LargestString
= (GetStringWidth (StackString
) / 2);
900 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
901 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
908 VA_START (Marker
, KeyValue
);
909 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
913 // Take the first key typed and report it back?
916 Status
= WaitForKeyStroke (&Key
);
917 ASSERT_EFI_ERROR (Status
);
918 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
922 Status
= WaitForKeyStroke (&Key
);
924 switch (Key
.UnicodeChar
) {
926 switch (Key
.ScanCode
) {
928 FreePool (TempString
);
929 FreePool (BufferedString
);
930 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
931 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
932 return EFI_DEVICE_ERROR
;
940 case CHAR_CARRIAGE_RETURN
:
941 SelectionComplete
= TRUE
;
942 FreePool (TempString
);
943 FreePool (BufferedString
);
944 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
945 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
950 if (StringBuffer
[0] != CHAR_NULL
) {
951 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
952 TempString
[Index
] = StringBuffer
[Index
];
955 // Effectively truncate string by 1 character
957 TempString
[Index
- 1] = CHAR_NULL
;
958 StrCpy (StringBuffer
, TempString
);
961 // break skipped on purpose
966 // If it is the beginning of the string, don't worry about checking maximum limits
968 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
969 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
970 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
971 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
972 KeyPad
[0] = Key
.UnicodeChar
;
973 KeyPad
[1] = CHAR_NULL
;
974 StrCat (StringBuffer
, KeyPad
);
975 StrCat (TempString
, KeyPad
);
978 // If the width of the input string is now larger than the screen, we nee to
979 // adjust the index to start printing portions of the string
981 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
983 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
985 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
986 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
991 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
992 BufferedString
[Count
] = StringBuffer
[Index
];
995 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
998 } while (!SelectionComplete
);
1001 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
1002 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
1007 Draw a pop up windows based on the dimension, number of lines and
1010 @param RequestedWidth The width of the pop-up.
1011 @param NumberOfLines The number of lines.
1012 @param Marker The variable argument list for the list of string to be printed.
1017 IN UINTN RequestedWidth
,
1018 IN UINTN NumberOfLines
,
1030 UINTN DimensionsWidth
;
1031 UINTN DimensionsHeight
;
1033 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1034 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
1036 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1038 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
1039 RequestedWidth
= DimensionsWidth
- 2;
1043 // Subtract the PopUp width from total Columns, allow for one space extra on
1044 // each end plus a border.
1046 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
1047 End
= Start
+ RequestedWidth
+ 1;
1049 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
1050 Bottom
= Top
+ NumberOfLines
+ 2;
1052 Character
= BOXDRAW_DOWN_RIGHT
;
1053 PrintCharAt (Start
, Top
, Character
);
1054 Character
= BOXDRAW_HORIZONTAL
;
1055 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1056 PrintChar (Character
);
1059 Character
= BOXDRAW_DOWN_LEFT
;
1060 PrintChar (Character
);
1061 Character
= BOXDRAW_VERTICAL
;
1064 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
1065 String
= VA_ARG (Marker
, CHAR16
*);
1068 // This will clear the background of the line - we never know who might have been
1069 // here before us. This differs from the next clear in that it used the non-reverse
1070 // video for normal printing.
1072 if (GetStringWidth (String
) / 2 > 1) {
1073 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
1077 // Passing in a space results in the assumption that this is where typing will occur
1079 if (String
[0] == L
' ') {
1080 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
1084 // Passing in a NULL results in a blank space
1086 if (String
[0] == CHAR_NULL
) {
1087 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
1091 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
1095 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1096 PrintCharAt (Start
, Index
+ 1, Character
);
1097 PrintCharAt (End
- 1, Index
+ 1, Character
);
1100 Character
= BOXDRAW_UP_RIGHT
;
1101 PrintCharAt (Start
, Bottom
- 1, Character
);
1102 Character
= BOXDRAW_HORIZONTAL
;
1103 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1104 PrintChar (Character
);
1107 Character
= BOXDRAW_UP_LEFT
;
1108 PrintChar (Character
);
1112 Draw a pop up windows based on the dimension, number of lines and
1115 @param RequestedWidth The width of the pop-up.
1116 @param NumberOfLines The number of lines.
1117 @param ... A series of text strings that displayed in the pop-up.
1122 CreateMultiStringPopUp (
1123 IN UINTN RequestedWidth
,
1124 IN UINTN NumberOfLines
,
1130 VA_START (Marker
, NumberOfLines
);
1132 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1139 Update status bar on the bottom of menu.
1141 @param Selection Current Selction info.
1142 @param MessageType The type of message to be shown.
1143 @param Flags The flags in Question header.
1144 @param State Set or clear.
1149 IN UI_MENU_SELECTION
*Selection
,
1150 IN UINTN MessageType
,
1156 CHAR16
*NvUpdateMessage
;
1157 CHAR16
*InputErrorMessage
;
1159 FORM_BROWSER_FORMSET
*LocalFormSet
;
1160 FORM_BROWSER_STATEMENT
*Question
;
1162 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1163 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1165 switch (MessageType
) {
1168 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1170 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1171 gScreenDimensions
.BottomRow
- 1,
1176 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1177 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1178 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1181 mInputError
= FALSE
;
1185 case NV_UPDATE_REQUIRED
:
1187 // Global setting support. Show configuration change on every form.
1190 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1192 if (Selection
!= NULL
&& Selection
->Statement
!= NULL
) {
1193 Question
= Selection
->Statement
;
1194 if (Question
->Storage
!= NULL
|| Question
->Operand
== EFI_IFR_DATE_OP
|| Question
->Operand
== EFI_IFR_TIME_OP
) {
1196 // Update only for Question value that need to be saved into Storage.
1198 Selection
->Form
->NvUpdateRequired
= TRUE
;
1202 if (Selection
== NULL
|| IsNvUpdateRequired (Selection
->FormSet
)) {
1203 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1205 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1206 gScreenDimensions
.BottomRow
- 1,
1211 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1212 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1214 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1215 gScreenDimensions
.BottomRow
- 1,
1222 case REFRESH_STATUS_BAR
:
1224 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1227 switch (gBrowserSettingScope
) {
1230 // Check the maintain list to see whether there is any change.
1232 Link
= GetFirstNode (&gBrowserFormSetList
);
1233 while (!IsNull (&gBrowserFormSetList
, Link
)) {
1234 LocalFormSet
= FORM_BROWSER_FORMSET_FROM_LINK (Link
);
1235 if (IsNvUpdateRequired(LocalFormSet
)) {
1236 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1239 Link
= GetNextNode (&gBrowserFormSetList
, Link
);
1244 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1255 FreePool (InputErrorMessage
);
1256 FreePool (NvUpdateMessage
);
1262 Get the supported width for a particular op-code
1264 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1265 @param Handle The handle in the HII database being used
1267 @return Returns the number of CHAR16 characters that is support.
1272 IN FORM_BROWSER_STATEMENT
*Statement
,
1273 IN EFI_HII_HANDLE Handle
1283 // See if the second text parameter is really NULL
1285 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1286 String
= GetToken (Statement
->TextTwo
, Handle
);
1287 Size
= StrLen (String
);
1291 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1292 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1293 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1294 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1295 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1297 // Allow a wide display if text op-code and no secondary text op-code
1299 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1301 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1303 Width
= (UINT16
) gPromptBlockWidth
;
1306 if (Statement
->InSubtitle
) {
1307 Width
-= SUBTITLE_INDENT
;
1310 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1314 Will copy LineWidth amount of a string in the OutputString buffer and return the
1315 number of CHAR16 characters that were copied into the OutputString buffer.
1316 The output string format is:
1317 Glyph Info + String info + '\0'.
1319 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
1321 @param InputString String description for this option.
1322 @param LineWidth Width of the desired string to extract in CHAR16
1324 @param GlyphWidth The glyph width of the begin of the char in the string.
1325 @param Index Where in InputString to start the copy process
1326 @param OutputString Buffer to copy the string into
1328 @return Returns the number of CHAR16 characters that were copied into the OutputString
1329 buffer, include extra glyph info and '\0' info.
1334 IN CHAR16
*InputString
,
1335 IN UINT16 LineWidth
,
1336 IN OUT UINT16
*GlyphWidth
,
1337 IN OUT UINTN
*Index
,
1338 OUT CHAR16
**OutputString
1343 UINT16 OriginalGlyphWidth
;
1345 UINT16 LastSpaceOffset
;
1346 UINT16 LastGlyphWidth
;
1348 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
1352 if (LineWidth
== 0 || *GlyphWidth
== 0) {
1357 // Save original glyph width.
1359 OriginalGlyphWidth
= *GlyphWidth
;
1360 LastGlyphWidth
= OriginalGlyphWidth
;
1362 LastSpaceOffset
= 0;
1365 // 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.
1366 // To avoid displaying this empty line in screen, just skip the two CHARs here.
1368 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1369 *Index
= *Index
+ 2;
1373 // Fast-forward the string and see if there is a carriage-return in the string
1375 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
1376 switch (InputString
[*Index
+ StrOffset
]) {
1385 case CHAR_CARRIAGE_RETURN
:
1392 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
1395 // Record the last space info in this line. Will be used in rewind.
1397 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
1398 LastSpaceOffset
= StrOffset
;
1399 LastGlyphWidth
= *GlyphWidth
;
1410 // Rewind the string from the maximum size until we see a space to break the line
1412 if (GlyphOffset
> LineWidth
) {
1414 // Rewind the string to last space char in this line.
1416 if (LastSpaceOffset
!= 0) {
1417 StrOffset
= LastSpaceOffset
;
1418 *GlyphWidth
= LastGlyphWidth
;
1421 // Roll back to last char in the line width.
1428 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
1430 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
1435 // Need extra glyph info and '\0' info, so +2.
1437 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
1438 if (*OutputString
== NULL
) {
1443 // Save the glyph info at the begin of the string, will used by Print function.
1445 if (OriginalGlyphWidth
== 1) {
1446 *(*OutputString
) = NARROW_CHAR
;
1448 *(*OutputString
) = WIDE_CHAR
;
1451 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
1453 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
1455 // Skip the space info at the begin of next line.
1457 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
1458 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
1460 // Skip the /n or /n/r info.
1462 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
1463 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
1465 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
1467 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
1469 // Skip the /r or /r/n info.
1471 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
1472 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
1474 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
1477 *Index
= (UINT16
) (*Index
+ StrOffset
);
1481 // Include extra glyph info and '\0' info, so +2.
1483 return StrOffset
+ 2;
1488 Update display lines for a Menu Option.
1490 @param Selection The user's selection.
1491 @param MenuOption The MenuOption to be checked.
1495 UpdateOptionSkipLines (
1496 IN UI_MENU_SELECTION
*Selection
,
1497 IN UI_MENU_OPTION
*MenuOption
1504 CHAR16
*OutputString
;
1505 CHAR16
*OptionString
;
1509 OptionString
= NULL
;
1510 Width
= (UINT16
) gOptionBlockWidth
;
1514 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1515 if (OptionString
== NULL
) {
1519 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1521 // If there is more string to process print on the next row and increment the Skip value
1523 if (StrLen (&OptionString
[Index
]) != 0) {
1526 // Since the Number of lines for this menu entry may or may not be reflected accurately
1527 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1528 // some testing to ensure we are keeping this in-sync.
1530 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1532 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1537 FreePool (OutputString
);
1540 if (OptionString
!= NULL
) {
1541 FreePool (OptionString
);
1547 Check whether this Menu Option could be highlighted.
1549 This is an internal function.
1551 @param MenuOption The MenuOption to be checked.
1553 @retval TRUE This Menu Option is selectable.
1554 @retval FALSE This Menu Option could not be selected.
1559 UI_MENU_OPTION
*MenuOption
1562 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1563 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1572 Determine if the menu is the last menu that can be selected.
1574 This is an internal function.
1576 @param Direction The scroll direction. False is down. True is up.
1577 @param CurrentPos The current focus.
1579 @return FALSE -- the menu isn't the last menu that can be selected.
1580 @return TRUE -- the menu is the last menu that can be selected.
1585 IN BOOLEAN Direction
,
1586 IN LIST_ENTRY
*CurrentPos
1591 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1593 if (Temp
== &gMenuOption
) {
1602 Move to next selectable statement.
1604 This is an internal function.
1606 @param Selection Menu selection.
1607 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1608 @param CurrentPosition Current position.
1609 @param GapToTop Gap position to top or bottom.
1611 @return The row distance from current MenuOption to next selectable MenuOption.
1613 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
1614 @retval Value Find the selectable menu, maybe the truly selectable, maybe the l
1615 last menu showing at current form.
1619 MoveToNextStatement (
1620 IN UI_MENU_SELECTION
*Selection
,
1622 IN OUT LIST_ENTRY
**CurrentPosition
,
1628 UI_MENU_OPTION
*NextMenuOption
;
1629 UI_MENU_OPTION
*PreMenuOption
;
1632 Pos
= *CurrentPosition
;
1633 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1636 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1638 // NextMenuOption->Row == 0 means this menu has not calculate
1639 // the NextMenuOption->Skip value yet, just calculate here.
1641 if (NextMenuOption
->Row
== 0) {
1642 UpdateOptionSkipLines (Selection
, NextMenuOption
);
1645 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1647 // In this case, still can't find the selectable menu,
1648 // return the last one in the showing form.
1650 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1651 NextMenuOption
= PreMenuOption
;
1656 // Current Position doesn't need to be caculated when go up.
1657 // Caculate distanct at first when go up
1659 Distance
+= NextMenuOption
->Skip
;
1662 if (IsSelectable (NextMenuOption
)) {
1667 // Arrive at begin of the menu list.
1669 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1676 // In this case, still can't find the selectable menu,
1677 // return the last one in the showing form.
1679 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1680 NextMenuOption
= PreMenuOption
;
1684 Distance
+= NextMenuOption
->Skip
;
1687 PreMenuOption
= NextMenuOption
;
1688 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1691 *CurrentPosition
= &NextMenuOption
->Link
;
1697 Adjust Data and Time position accordingly.
1698 Data format : [01/02/2004] [11:22:33]
1699 Line number : 0 0 1 0 0 1
1701 This is an internal function.
1703 @param DirectionUp the up or down direction. False is down. True is
1705 @param CurrentPosition Current position. On return: Point to the last
1706 Option (Year or Second) if up; Point to the first
1707 Option (Month or Hour) if down.
1709 @return Return line number to pad. It is possible that we stand on a zero-advance
1710 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1714 AdjustDateAndTimePosition (
1715 IN BOOLEAN DirectionUp
,
1716 IN OUT LIST_ENTRY
**CurrentPosition
1720 LIST_ENTRY
*NewPosition
;
1721 UI_MENU_OPTION
*MenuOption
;
1722 UINTN PadLineNumber
;
1725 NewPosition
= *CurrentPosition
;
1726 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1728 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1729 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1731 // Calculate the distance from current position to the last Date/Time MenuOption
1734 while (MenuOption
->Skip
== 0) {
1736 NewPosition
= NewPosition
->ForwardLink
;
1737 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1741 NewPosition
= *CurrentPosition
;
1744 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1745 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1746 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1747 // checking can be done.
1749 while (Count
++ < 2) {
1750 NewPosition
= NewPosition
->BackLink
;
1754 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1755 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1756 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1757 // checking can be done.
1759 while (Count
-- > 0) {
1760 NewPosition
= NewPosition
->ForwardLink
;
1764 *CurrentPosition
= NewPosition
;
1767 return PadLineNumber
;
1771 Find HII Handle in the HII database associated with given Device Path.
1773 If DevicePath is NULL, then ASSERT.
1775 @param DevicePath Device Path associated with the HII package list
1778 @retval Handle HII package list Handle associated with the Device
1780 @retval NULL Hii Package list handle is not found.
1785 DevicePathToHiiHandle (
1786 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1790 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1795 EFI_HANDLE DriverHandle
;
1796 EFI_HII_HANDLE
*HiiHandles
;
1797 EFI_HII_HANDLE HiiHandle
;
1799 ASSERT (DevicePath
!= NULL
);
1801 TmpDevicePath
= DevicePath
;
1803 // Locate Device Path Protocol handle buffer
1805 Status
= gBS
->LocateDevicePath (
1806 &gEfiDevicePathProtocolGuid
,
1810 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1815 // Retrieve all HII Handles from HII database
1817 BufferSize
= 0x1000;
1818 HiiHandles
= AllocatePool (BufferSize
);
1819 ASSERT (HiiHandles
!= NULL
);
1820 Status
= mHiiDatabase
->ListPackageLists (
1822 EFI_HII_PACKAGE_TYPE_ALL
,
1827 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1828 FreePool (HiiHandles
);
1829 HiiHandles
= AllocatePool (BufferSize
);
1830 ASSERT (HiiHandles
!= NULL
);
1832 Status
= mHiiDatabase
->ListPackageLists (
1834 EFI_HII_PACKAGE_TYPE_ALL
,
1841 if (EFI_ERROR (Status
)) {
1842 FreePool (HiiHandles
);
1847 // Search Hii Handle by Driver Handle
1850 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1851 for (Index
= 0; Index
< HandleCount
; Index
++) {
1852 Status
= mHiiDatabase
->GetPackageListHandle (
1857 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1858 HiiHandle
= HiiHandles
[Index
];
1863 FreePool (HiiHandles
);
1868 Find HII Handle in the HII database associated with given form set guid.
1870 If FormSetGuid is NULL, then ASSERT.
1872 @param ComparingGuid FormSet Guid associated with the HII package list
1875 @retval Handle HII package list Handle associated with the Device
1877 @retval NULL Hii Package list handle is not found.
1881 FormSetGuidToHiiHandle (
1882 EFI_GUID
*ComparingGuid
1885 EFI_HII_HANDLE
*HiiHandles
;
1887 EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
;
1891 UINT32 PackageListLength
;
1892 EFI_HII_PACKAGE_HEADER PackageHeader
;
1896 EFI_HII_HANDLE HiiHandle
;
1898 ASSERT (ComparingGuid
!= NULL
);
1902 // Get all the Hii handles
1904 HiiHandles
= HiiGetHiiHandles (NULL
);
1905 ASSERT (HiiHandles
!= NULL
);
1908 // Search for formset of each class type
1910 for (Index
= 0; HiiHandles
[Index
] != NULL
; Index
++) {
1912 HiiPackageList
= NULL
;
1913 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1914 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1915 HiiPackageList
= AllocatePool (BufferSize
);
1916 ASSERT (HiiPackageList
!= NULL
);
1918 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1920 if (EFI_ERROR (Status
) || HiiPackageList
== NULL
) {
1925 // Get Form package from this HII package List
1927 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
1929 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
1931 while (Offset
< PackageListLength
) {
1932 Package
= ((UINT8
*) HiiPackageList
) + Offset
;
1933 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
1935 if (PackageHeader
.Type
== EFI_HII_PACKAGE_FORMS
) {
1937 // Search FormSet in this Form Package
1939 Offset2
= sizeof (EFI_HII_PACKAGE_HEADER
);
1940 while (Offset2
< PackageHeader
.Length
) {
1941 OpCodeData
= Package
+ Offset2
;
1943 if (((EFI_IFR_OP_HEADER
*) OpCodeData
)->OpCode
== EFI_IFR_FORM_SET_OP
) {
1945 // Try to compare against formset GUID
1947 if (CompareGuid (ComparingGuid
, (EFI_GUID
*)(OpCodeData
+ sizeof (EFI_IFR_OP_HEADER
)))) {
1948 HiiHandle
= HiiHandles
[Index
];
1953 Offset2
+= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
1956 if (HiiHandle
!= NULL
) {
1959 Offset
+= PackageHeader
.Length
;
1962 FreePool (HiiPackageList
);
1963 if (HiiHandle
!= NULL
) {
1968 FreePool (HiiHandles
);
1974 Transfer the device path string to binary format.
1976 @param StringPtr The device path string info.
1978 @retval Device path binary info.
1981 EFI_DEVICE_PATH_PROTOCOL
*
1982 ConvertDevicePathFromText (
1983 IN CHAR16
*StringPtr
1987 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1989 UINT8
*DevicePathBuffer
;
1993 ASSERT (StringPtr
!= NULL
);
1995 BufferSize
= StrLen (StringPtr
) / 2;
1996 DevicePath
= AllocatePool (BufferSize
);
1997 ASSERT (DevicePath
!= NULL
);
2000 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2002 DevicePathBuffer
= (UINT8
*) DevicePath
;
2003 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2004 TemStr
[0] = StringPtr
[Index
];
2005 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2006 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2008 // Invalid Hex Char as the tail.
2012 if ((Index
& 1) == 0) {
2013 DevicePathBuffer
[Index
/2] = DigitUint8
;
2015 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2023 Process the goto op code, update the info in the selection structure.
2025 @param Statement The statement belong to goto op code.
2026 @param Selection The selection info.
2027 @param Repaint Whether need to repaint the menu.
2028 @param NewLine Whether need to create new line.
2030 @retval EFI_SUCCESS The menu process successfully.
2031 @return Other value if the process failed.
2035 IN OUT FORM_BROWSER_STATEMENT
*Statement
,
2036 IN OUT UI_MENU_SELECTION
*Selection
,
2037 OUT BOOLEAN
*Repaint
,
2038 OUT BOOLEAN
*NewLine
2042 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2043 FORM_BROWSER_FORM
*RefForm
;
2046 UI_MENU_LIST
*MenuList
;
2047 BOOLEAN UpdateFormInfo
;
2049 Status
= EFI_SUCCESS
;
2050 UpdateFormInfo
= TRUE
;
2054 // Prepare the device path check, get the device path info first.
2056 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0) {
2057 StringPtr
= GetToken (Statement
->HiiValue
.Value
.ref
.DevicePath
, Selection
->FormSet
->HiiHandle
);
2061 // Check whether the device path string is a valid string.
2063 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0 && StringPtr
!= NULL
) {
2064 if (Selection
->Form
->ModalForm
) {
2068 // Goto another Hii Package list
2070 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2071 DevicePath
= ConvertDevicePathFromText (StringPtr
);
2073 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2074 FreePool (DevicePath
);
2075 FreePool (StringPtr
);
2077 if (Selection
->Handle
== NULL
) {
2079 // If target Hii Handle not found, exit
2081 Selection
->Action
= UI_ACTION_EXIT
;
2082 Selection
->Statement
= NULL
;
2086 CopyMem (&Selection
->FormSetGuid
,&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
2087 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
2088 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2089 } else if (!CompareGuid (&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, &gZeroGuid
)) {
2090 if (Selection
->Form
->ModalForm
) {
2094 // Goto another Formset, check for uncommitted data
2096 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2098 Selection
->Handle
= FormSetGuidToHiiHandle(&Statement
->HiiValue
.Value
.ref
.FormSetGuid
);
2099 if (Selection
->Handle
== NULL
) {
2101 // If target Hii Handle not found, exit
2103 Selection
->Action
= UI_ACTION_EXIT
;
2104 Selection
->Statement
= NULL
;
2108 CopyMem (&Selection
->FormSetGuid
, &Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
2109 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
2110 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2111 } else if (Statement
->HiiValue
.Value
.ref
.FormId
!= 0) {
2113 // Check whether target From is suppressed.
2115 RefForm
= IdToForm (Selection
->FormSet
, Statement
->HiiValue
.Value
.ref
.FormId
);
2117 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2118 if (EvaluateExpressionList(RefForm
->SuppressExpression
, TRUE
, Selection
->FormSet
, RefForm
) != ExpressFalse
) {
2120 // Form is suppressed.
2123 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2124 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2125 if (Repaint
!= NULL
) {
2133 // Goto another form inside this formset,
2135 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2137 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
2138 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2139 } else if (Statement
->HiiValue
.Value
.ref
.QuestionId
!= 0) {
2141 // Goto another Question
2143 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2145 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2146 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2148 if (Repaint
!= NULL
) {
2151 if (NewLine
!= NULL
) {
2155 UpdateFormInfo
= FALSE
;
2157 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2158 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2160 UpdateFormInfo
= FALSE
;
2163 if (UpdateFormInfo
) {
2165 // Link current form so that we can always go back when someone hits the ESC
2167 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
2168 if (MenuList
== NULL
&& Selection
->CurrentMenu
!= NULL
) {
2169 MenuList
= UiAddMenuList (Selection
->CurrentMenu
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
2177 Display menu and wait for user to select one menu option, then return it.
2178 If AutoBoot is enabled, then if user doesn't select any option,
2179 after period of time, it will automatically return the first menu option.
2181 @param Selection Menu selection.
2183 @retval EFI_SUCESSS This function always return successfully for now.
2188 IN OUT UI_MENU_SELECTION
*Selection
2193 UINTN DistanceValue
;
2204 CHAR16
*OptionString
;
2205 CHAR16
*OutputString
;
2207 CHAR16
*HelpHeaderString
;
2208 CHAR16
*HelpBottomString
;
2214 BOOLEAN InitializedFlag
;
2219 LIST_ENTRY
*TopOfScreen
;
2220 LIST_ENTRY
*SavedListEntry
;
2221 UI_MENU_OPTION
*MenuOption
;
2222 UI_MENU_OPTION
*NextMenuOption
;
2223 UI_MENU_OPTION
*SavedMenuOption
;
2224 UI_MENU_OPTION
*PreviousMenuOption
;
2225 UI_CONTROL_FLAG ControlFlag
;
2226 EFI_SCREEN_DESCRIPTOR LocalScreen
;
2227 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
2228 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
2229 UI_SCREEN_OPERATION ScreenOperation
;
2230 UINT8 MinRefreshInterval
;
2232 FORM_BROWSER_STATEMENT
*Statement
;
2233 UI_MENU_LIST
*CurrentMenu
;
2234 UINTN ModalSkipColumn
;
2235 BROWSER_HOT_KEY
*HotKey
;
2236 UINTN HelpPageIndex
;
2237 UINTN HelpPageCount
;
2240 UINTN HelpHeaderLine
;
2241 UINTN HelpBottomLine
;
2242 BOOLEAN MultiHelpPage
;
2244 UINT16 EachLineWidth
;
2245 UINT16 HeaderLineWidth
;
2246 UINT16 BottomLineWidth
;
2248 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
2250 Status
= EFI_SUCCESS
;
2252 HelpHeaderString
= NULL
;
2253 HelpBottomString
= NULL
;
2254 OptionString
= NULL
;
2255 ScreenOperation
= UiNoOperation
;
2257 MinRefreshInterval
= 0;
2265 MultiHelpPage
= FALSE
;
2267 HeaderLineWidth
= 0;
2268 BottomLineWidth
= 0;
2269 OutputString
= NULL
;
2273 MenuRefreshEntry
= gMenuRefreshHead
;
2275 NextMenuOption
= NULL
;
2276 PreviousMenuOption
= NULL
;
2277 SavedMenuOption
= NULL
;
2279 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
2281 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2283 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
2284 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2285 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2287 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2288 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2291 if (Selection
->Form
->ModalForm
) {
2292 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
2294 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2297 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- gFooterHeight
- SCROLL_ARROW_HEIGHT
- 1;
2299 Selection
->TopRow
= TopRow
;
2300 Selection
->BottomRow
= BottomRow
;
2301 Selection
->PromptCol
= Col
;
2302 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2303 Selection
->Statement
= NULL
;
2305 TopOfScreen
= gMenuOption
.ForwardLink
;
2310 // Find current Menu
2312 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
2313 if (CurrentMenu
== NULL
) {
2315 // Current menu not found, add it to the menu tree
2317 CurrentMenu
= UiAddMenuList (NULL
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
2319 ASSERT (CurrentMenu
!= NULL
);
2320 Selection
->CurrentMenu
= CurrentMenu
;
2322 if (Selection
->QuestionId
== 0) {
2324 // Highlight not specified, fetch it from cached menu
2326 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
2327 Selection
->Sequence
= CurrentMenu
->Sequence
;
2331 // Init option as the current user's selection
2333 InitializedFlag
= TRUE
;
2334 NewPos
= gMenuOption
.ForwardLink
;
2336 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2337 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
2339 ControlFlag
= CfInitialization
;
2340 Selection
->Action
= UI_ACTION_NONE
;
2342 switch (ControlFlag
) {
2343 case CfInitialization
:
2344 if (IsListEmpty (&gMenuOption
)) {
2345 ControlFlag
= CfReadKey
;
2347 ControlFlag
= CfCheckSelection
;
2351 case CfCheckSelection
:
2352 if (Selection
->Action
!= UI_ACTION_NONE
) {
2353 ControlFlag
= CfExit
;
2355 ControlFlag
= CfRepaint
;
2360 ControlFlag
= CfRefreshHighLight
;
2370 Temp
= (UINTN
) SkipValue
;
2371 Temp2
= (UINTN
) SkipValue
;
2374 // 1. Clear the screen.
2376 if (Selection
->Form
->ModalForm
) {
2378 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
2379 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
2380 TopRow
- SCROLL_ARROW_HEIGHT
,
2381 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2382 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2386 LocalScreen
.LeftColumn
,
2387 LocalScreen
.RightColumn
,
2388 TopRow
- SCROLL_ARROW_HEIGHT
,
2389 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2390 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2393 UiFreeRefreshList ();
2394 MinRefreshInterval
= 0;
2397 // 2.Paint the menu.
2399 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2400 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2401 MenuOption
->Row
= Row
;
2402 MenuOption
->Col
= Col
;
2403 if (Selection
->Form
->ModalForm
) {
2404 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
2406 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2409 Statement
= MenuOption
->ThisTag
;
2410 if (Statement
->InSubtitle
) {
2411 MenuOption
->Col
+= SUBTITLE_INDENT
;
2414 if (MenuOption
->GrayOut
) {
2415 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2417 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2418 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2422 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2426 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
2428 // Print Arrow for Goto button.
2431 MenuOption
->Col
- 2,
2434 GEOMETRICSHAPE_RIGHT_TRIANGLE
2439 // 2.1. Paint the description.
2441 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2443 // Temp means need to skip how many lines from the start.
2445 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2446 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
2449 // If there is more string to process print on the next row and increment the Skip value
2451 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2457 FreePool (OutputString
);
2467 // 2.2. Paint the option string.
2469 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2470 if (EFI_ERROR (Status
)) {
2472 // Repaint to clear possible error prompt pop-up
2476 ControlFlag
= CfRepaint
;
2480 if (OptionString
!= NULL
) {
2481 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2482 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
2485 Width
= (UINT16
) gOptionBlockWidth
;
2489 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2490 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2491 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2494 // If there is more string to process print on the next row and increment the Skip value
2496 if (StrLen (&OptionString
[Index
]) != 0) {
2500 // Since the Number of lines for this menu entry may or may not be reflected accurately
2501 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2502 // some testing to ensure we are keeping this in-sync.
2504 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2506 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2512 FreePool (OutputString
);
2521 FreePool (OptionString
);
2525 // 2.4 Special process for Test opcode with test two.
2527 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
2528 if (gMenuEventGuidRefreshHead
== NULL
) {
2529 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2530 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
2532 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
2533 while (MenuUpdateEntry
->Next
!= NULL
) {
2534 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2536 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2537 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2539 ASSERT (MenuUpdateEntry
!= NULL
);
2540 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
2541 ASSERT (!EFI_ERROR (Status
));
2542 MenuUpdateEntry
->MenuOption
= MenuOption
;
2543 MenuUpdateEntry
->Selection
= Selection
;
2544 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
2545 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
2546 if (MenuOption
->GrayOut
) {
2547 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2549 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2554 // If Question request refresh, register the op-code
2556 if (Statement
->RefreshInterval
!= 0) {
2558 // Menu will be refreshed at minimal interval of all Questions
2559 // which have refresh request
2561 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
2562 MinRefreshInterval
= Statement
->RefreshInterval
;
2565 if (gMenuRefreshHead
== NULL
) {
2566 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2567 gMenuRefreshHead
= MenuRefreshEntry
;
2569 MenuRefreshEntry
= gMenuRefreshHead
;
2570 while (MenuRefreshEntry
->Next
!= NULL
) {
2571 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2573 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2574 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2576 ASSERT (MenuRefreshEntry
!= NULL
);
2577 MenuRefreshEntry
->MenuOption
= MenuOption
;
2578 MenuRefreshEntry
->Selection
= Selection
;
2579 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2580 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2581 if (MenuOption
->GrayOut
) {
2582 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2584 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2589 // If this is a text op with secondary text information
2591 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2592 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2594 Width
= (UINT16
) gOptionBlockWidth
;
2598 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2599 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2600 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2603 // If there is more string to process print on the next row and increment the Skip value
2605 if (StrLen (&StringPtr
[Index
]) != 0) {
2609 // Since the Number of lines for this menu entry may or may not be reflected accurately
2610 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2611 // some testing to ensure we are keeping this in-sync.
2613 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2615 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2621 FreePool (OutputString
);
2628 FreePool (StringPtr
);
2630 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2633 // 3. Update the row info which will be used by next menu.
2635 if (Link
== TopOfScreen
) {
2636 Row
+= MenuOption
->Skip
- SkipValue
;
2638 Row
+= MenuOption
->Skip
;
2641 if (Row
> BottomRow
) {
2642 if (!ValueIsScroll (FALSE
, Link
)) {
2646 Row
= BottomRow
+ 1;
2651 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2656 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2658 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2659 TopRow
- SCROLL_ARROW_HEIGHT
,
2663 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2667 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2669 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2670 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2674 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2681 case CfRefreshHighLight
:
2683 // MenuOption: Last menu option that need to remove hilight
2684 // MenuOption is set to NULL in Repaint
2685 // NewPos: Current menu option that need to hilight
2687 ControlFlag
= CfUpdateHelpString
;
2688 if (TopOfScreen
== &MenuOption
->Link
) {
2693 if (NewPos
== TopOfScreen
) {
2698 if (InitializedFlag
) {
2699 InitializedFlag
= FALSE
;
2700 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
2704 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2705 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2707 SavedValue
= Repaint
;
2710 if (Selection
->QuestionId
!= 0) {
2711 NewPos
= gMenuOption
.ForwardLink
;
2712 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2714 while ((SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
||
2715 SavedMenuOption
->Sequence
!= Selection
->Sequence
) &&
2716 NewPos
->ForwardLink
!= &gMenuOption
) {
2717 NewPos
= NewPos
->ForwardLink
;
2718 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2720 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2722 // Target Question found, find its MenuOption
2726 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2727 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2728 Index
+= SavedMenuOption
->Skip
;
2729 if (Link
== TopOfScreen
) {
2732 Link
= Link
->ForwardLink
;
2734 if (NewPos
== Link
) {
2735 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2739 // Not find the selected menu in current show page.
2740 // Have two case to enter this if:
2741 // 1. Not find the menu at current page.
2742 // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.
2743 // For case 2, has an exception: The menu can show more than one pages and now only this menu shows.
2745 // Base on the selected menu will show at the bottom of the page,
2746 // select the menu which will show at the top of the page.
2748 if (Link
!= NewPos
|| Index
> BottomRow
||
2749 (Link
== NewPos
&& (SavedMenuOption
->Row
+ SavedMenuOption
->Skip
- 1 > BottomRow
) && (Link
!= TopOfScreen
))) {
2751 // Find the MenuOption which has the skip value for Date/Time opcode.
2753 AdjustDateAndTimePosition(FALSE
, &NewPos
);
2755 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2757 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2759 // SavedMenuOption->Row == 0 means the menu not show yet.
2761 if (SavedMenuOption
->Row
== 0) {
2762 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2766 // Base on the selected menu will show at the bottome of next page,
2767 // select the menu show at the top of the next page.
2770 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= BottomRow
+ 1; ) {
2771 Link
= Link
->BackLink
;
2772 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2773 if (SavedMenuOption
->Row
== 0) {
2774 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2776 Index
+= SavedMenuOption
->Skip
;
2780 // Found the menu which will show at the top of the page.
2782 if (Link
== NewPos
) {
2784 // The menu can show more than one pages, just show the menu at the top of the page.
2790 // Check whether need to skip some line for menu shows at the top of the page.
2792 SkipValue
= Index
- BottomRow
- 1;
2793 if (SkipValue
> 0 && SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
2797 TopOfScreen
= Link
->ForwardLink
;
2803 ControlFlag
= CfRepaint
;
2808 // Target Question not found, highlight the default menu option
2810 NewPos
= TopOfScreen
;
2813 Selection
->QuestionId
= 0;
2816 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2817 if (MenuOption
!= NULL
) {
2819 // Remove highlight on last Menu Option
2821 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2822 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2823 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2824 if (OptionString
!= NULL
) {
2825 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2826 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2828 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2831 Width
= (UINT16
) gOptionBlockWidth
;
2832 OriginalRow
= MenuOption
->Row
;
2835 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2836 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2837 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2840 // If there is more string to process print on the next row and increment the Skip value
2842 if (StrLen (&OptionString
[Index
]) != 0) {
2848 FreePool (OutputString
);
2854 MenuOption
->Row
= OriginalRow
;
2856 FreePool (OptionString
);
2859 if (MenuOption
->GrayOut
) {
2860 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2861 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2862 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2865 OriginalRow
= MenuOption
->Row
;
2866 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2869 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2870 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2871 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2874 // If there is more string to process print on the next row and increment the Skip value
2876 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2882 FreePool (OutputString
);
2888 MenuOption
->Row
= OriginalRow
;
2889 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2895 // This is the current selected statement
2897 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2898 Statement
= MenuOption
->ThisTag
;
2899 Selection
->Statement
= Statement
;
2900 if (!IsSelectable (MenuOption
)) {
2901 Repaint
= SavedValue
;
2902 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2907 // Record highlight for current menu
2909 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2910 CurrentMenu
->Sequence
= MenuOption
->Sequence
;
2913 // Set reverse attribute
2915 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2916 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2919 // Assuming that we have a refresh linked-list created, lets annotate the
2920 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2921 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2923 if (gMenuRefreshHead
!= NULL
) {
2924 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2925 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2926 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2928 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2930 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2931 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2936 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2937 if (OptionString
!= NULL
) {
2938 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2939 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2941 Width
= (UINT16
) gOptionBlockWidth
;
2943 OriginalRow
= MenuOption
->Row
;
2946 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2947 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2948 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2951 // If there is more string to process print on the next row and increment the Skip value
2953 if (StrLen (&OptionString
[Index
]) != 0) {
2959 FreePool (OutputString
);
2965 MenuOption
->Row
= OriginalRow
;
2967 FreePool (OptionString
);
2970 OriginalRow
= MenuOption
->Row
;
2972 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2975 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2976 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2977 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2980 // If there is more string to process print on the next row and increment the Skip value
2982 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2988 FreePool (OutputString
);
2994 MenuOption
->Row
= OriginalRow
;
2999 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
3002 // Clear reverse attribute
3004 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
3007 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
3008 // if we didn't break halfway when process CfRefreshHighLight.
3010 Repaint
= SavedValue
;
3013 case CfUpdateHelpString
:
3014 ControlFlag
= CfPrepareToReadKey
;
3015 if (Selection
->Form
->ModalForm
) {
3019 if (Repaint
|| NewLine
) {
3021 // Don't print anything if it is a NULL help token
3023 ASSERT(MenuOption
!= NULL
);
3024 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
3027 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
3030 RowCount
= BottomRow
- TopRow
;
3033 // 1.Calculate how many line the help string need to print.
3035 if (HelpString
!= NULL
) {
3036 FreePool (HelpString
);
3038 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
3039 if (HelpLine
> RowCount
) {
3040 MultiHelpPage
= TRUE
;
3041 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
3042 if (HelpHeaderString
!= NULL
) {
3043 FreePool (HelpHeaderString
);
3045 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, RowCount
);
3046 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
3047 if (HelpBottomString
!= NULL
) {
3048 FreePool (HelpBottomString
);
3050 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, RowCount
);
3052 // Calculate the help page count.
3054 if (HelpLine
> 2 * RowCount
- 2) {
3055 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
3056 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
3063 MultiHelpPage
= FALSE
;
3068 // Clean the help field first.
3071 LocalScreen
.RightColumn
- gHelpBlockWidth
,
3072 LocalScreen
.RightColumn
,
3075 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
3079 // Check whether need to show the 'More(U/u)' at the begin.
3080 // Base on current direct info, here shows aligned to the right side of the column.
3081 // If the direction is multi line and aligned to right side may have problem, so
3082 // add ASSERT code here.
3084 if (HelpPageIndex
> 0) {
3085 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
| FIELD_BACKGROUND
);
3086 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
3087 ASSERT (HelpHeaderLine
== 1);
3088 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
3090 LocalScreen
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
3092 &HelpHeaderString
[Index
* HeaderLineWidth
]
3097 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
3099 // Print the help string info.
3101 if (!MultiHelpPage
) {
3102 for (Index
= 0; Index
< HelpLine
; Index
++) {
3104 LocalScreen
.RightColumn
- gHelpBlockWidth
,
3106 &HelpString
[Index
* EachLineWidth
]
3109 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, LocalScreen
.RightColumn
-1, BottomRow
);
3111 if (HelpPageIndex
== 0) {
3112 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
3114 LocalScreen
.RightColumn
- gHelpBlockWidth
,
3116 &HelpString
[Index
* EachLineWidth
]
3120 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
3121 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
3123 LocalScreen
.RightColumn
- gHelpBlockWidth
,
3124 Index
+ TopRow
+ HelpHeaderLine
,
3125 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
]
3128 if (HelpPageIndex
== HelpPageCount
- 1) {
3129 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, LocalScreen
.RightColumn
-1, BottomRow
);
3135 // Check whether need to print the 'More(D/d)' at the bottom.
3136 // Base on current direct info, here shows aligned to the right side of the column.
3137 // If the direction is multi line and aligned to right side may have problem, so
3138 // add ASSERT code here.
3140 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
3141 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
| FIELD_BACKGROUND
);
3142 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
3143 ASSERT (HelpBottomLine
== 1);
3144 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
3146 LocalScreen
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
3147 Index
+ BottomRow
- HelpBottomLine
,
3148 &HelpBottomString
[Index
* BottomLineWidth
]
3153 // Reset this flag every time we finish using it.
3159 case CfPrepareToReadKey
:
3160 ControlFlag
= CfReadKey
;
3161 ScreenOperation
= UiNoOperation
;
3165 ControlFlag
= CfScreenOperation
;
3168 // Wait for user's selection
3171 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3172 if (!EFI_ERROR (Status
)) {
3177 // If we encounter error, continue to read another key in.
3179 if (Status
!= EFI_NOT_READY
) {
3183 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
3184 ASSERT_EFI_ERROR (Status
);
3186 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
3188 // IFR is updated in Callback of refresh opcode, re-parse it
3190 ControlFlag
= CfCheckSelection
;
3191 Selection
->Statement
= NULL
;
3196 if (ControlFlag
== CfCheckSelection
) {
3200 switch (Key
.UnicodeChar
) {
3201 case CHAR_CARRIAGE_RETURN
:
3202 if(MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3203 ControlFlag
= CfReadKey
;
3207 ScreenOperation
= UiSelect
;
3212 // We will push the adjustment of these numeric values directly to the input handler
3213 // NOTE: we won't handle manual input numeric
3218 // If the screen has no menu items, and the user didn't select UiReset
3219 // ignore the selection and go back to reading keys.
3221 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3222 ControlFlag
= CfReadKey
;
3226 ASSERT(MenuOption
!= NULL
);
3227 Statement
= MenuOption
->ThisTag
;
3228 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
3229 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
3230 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
3232 if (Key
.UnicodeChar
== '+') {
3233 gDirection
= SCAN_RIGHT
;
3235 gDirection
= SCAN_LEFT
;
3237 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
3238 if (EFI_ERROR (Status
)) {
3240 // Repaint to clear possible error prompt pop-up
3245 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3247 if (OptionString
!= NULL
) {
3248 FreePool (OptionString
);
3254 ScreenOperation
= UiUp
;
3259 ScreenOperation
= UiDown
;
3263 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
3265 // If the screen has no menu items, and the user didn't select UiReset
3266 // ignore the selection and go back to reading keys.
3268 if(IsListEmpty (&gMenuOption
)) {
3269 ControlFlag
= CfReadKey
;
3273 ASSERT(MenuOption
!= NULL
);
3274 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3275 ScreenOperation
= UiSelect
;
3282 if (!MultiHelpPage
) {
3283 ControlFlag
= CfReadKey
;
3286 ControlFlag
= CfUpdateHelpString
;
3287 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3292 if (!MultiHelpPage
) {
3293 ControlFlag
= CfReadKey
;
3296 ControlFlag
= CfUpdateHelpString
;
3297 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3301 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3302 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3303 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3308 if (Selection
->Form
->ModalForm
&& (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3310 // ModalForm has no ESC key and Hot Key.
3312 ControlFlag
= CfReadKey
;
3313 } else if (Index
== mScanCodeNumber
) {
3315 // Check whether Key matches the registered hot key.
3318 if ((gBrowserSettingScope
== SystemLevel
) || (gFunctionKeySetting
!= NONE_FUNCTION_KEY_SETTING
)) {
3319 HotKey
= GetHotKeyFromRegisterList (&Key
);
3321 if (HotKey
!= NULL
) {
3322 ScreenOperation
= UiHotKey
;
3329 case CfScreenOperation
:
3330 if (ScreenOperation
!= UiReset
) {
3332 // If the screen has no menu items, and the user didn't select UiReset
3333 // ignore the selection and go back to reading keys.
3335 if (IsListEmpty (&gMenuOption
)) {
3336 ControlFlag
= CfReadKey
;
3342 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
3345 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3346 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3353 ControlFlag
= CfCheckSelection
;
3355 ASSERT(MenuOption
!= NULL
);
3356 Statement
= MenuOption
->ThisTag
;
3357 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
3362 // Keep highlight on current MenuOption
3364 Selection
->QuestionId
= Statement
->QuestionId
;
3366 switch (Statement
->Operand
) {
3367 case EFI_IFR_REF_OP
:
3368 ProcessGotoOpCode(Statement
, Selection
, &Repaint
, &NewLine
);
3371 case EFI_IFR_ACTION_OP
:
3373 // Process the Config string <ConfigResp>
3375 Status
= ProcessQuestionConfig (Selection
, Statement
);
3377 if (EFI_ERROR (Status
)) {
3382 // The action button may change some Question value, so refresh the form
3384 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3387 case EFI_IFR_RESET_BUTTON_OP
:
3389 // Reset Question to default value specified by DefaultId
3391 ControlFlag
= CfUiDefault
;
3392 DefaultId
= Statement
->DefaultId
;
3397 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3399 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
3400 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
3402 if (EFI_ERROR (Status
)) {
3405 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
3407 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3410 if (OptionString
!= NULL
) {
3411 FreePool (OptionString
);
3419 // We come here when someone press ESC
3421 ControlFlag
= CfCheckSelection
;
3422 FindNextMenu (Selection
, &Repaint
, &NewLine
);
3426 ControlFlag
= CfCheckSelection
;
3427 ASSERT(MenuOption
!= NULL
);
3428 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3429 if (MenuOption
->Sequence
!= 0) {
3431 // In the middle or tail of the Date/Time op-code set, go left.
3433 ASSERT(NewPos
!= NULL
);
3434 NewPos
= NewPos
->BackLink
;
3440 ControlFlag
= CfCheckSelection
;
3441 ASSERT(MenuOption
!= NULL
);
3442 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3443 if (MenuOption
->Sequence
!= 2) {
3445 // In the middle or tail of the Date/Time op-code set, go left.
3447 ASSERT(NewPos
!= NULL
);
3448 NewPos
= NewPos
->ForwardLink
;
3454 ControlFlag
= CfCheckSelection
;
3456 SavedListEntry
= NewPos
;
3458 ASSERT(NewPos
!= NULL
);
3460 // Adjust Date/Time position before we advance forward.
3462 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3463 if (NewPos
->BackLink
!= &gMenuOption
) {
3464 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3465 ASSERT (MenuOption
!= NULL
);
3467 NewPos
= NewPos
->BackLink
;
3469 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3470 if (PreviousMenuOption
->Row
== 0) {
3471 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3473 DistanceValue
= PreviousMenuOption
->Skip
;
3475 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
3476 Difference
= MoveToNextStatement (Selection
, TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
3478 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3480 if (Difference
< 0) {
3482 // We hit the begining MenuOption that can be focused
3483 // so we simply scroll to the top.
3485 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3486 TopOfScreen
= gMenuOption
.ForwardLink
;
3490 // Scroll up to the last page when we have arrived at top page.
3492 NewPos
= &gMenuOption
;
3493 TopOfScreen
= &gMenuOption
;
3494 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3495 ScreenOperation
= UiPageUp
;
3496 ControlFlag
= CfScreenOperation
;
3499 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
3501 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3503 TopOfScreen
= NewPos
;
3506 } else if (!IsSelectable (NextMenuOption
)) {
3508 // Continue to go up until scroll to next page or the selectable option is found.
3510 ScreenOperation
= UiUp
;
3511 ControlFlag
= CfScreenOperation
;
3515 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3517 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3518 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3519 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3520 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3523 // Scroll up to the last page.
3525 NewPos
= &gMenuOption
;
3526 TopOfScreen
= &gMenuOption
;
3527 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3528 ScreenOperation
= UiPageUp
;
3529 ControlFlag
= CfScreenOperation
;
3535 // SkipValue means lines is skipped when show the top menu option.
3537 ControlFlag
= CfCheckSelection
;
3539 ASSERT(NewPos
!= NULL
);
3541 // Already at the first menu option, so do nothing.
3543 if (NewPos
->BackLink
== &gMenuOption
) {
3553 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
3554 // form of options to be show, so just update the SkipValue to show the next
3555 // parts of options.
3557 if (SkipValue
> (INTN
) (BottomRow
- TopRow
+ 1)) {
3558 SkipValue
-= BottomRow
- TopRow
+ 1;
3564 // First minus the menu of the top screen, it's value is SkipValue.
3566 Index
= (BottomRow
+ 1) - SkipValue
;
3567 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
3568 Link
= Link
->BackLink
;
3569 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3570 if (PreviousMenuOption
->Row
== 0) {
3571 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3573 if (Index
< PreviousMenuOption
->Skip
) {
3576 Index
= Index
- PreviousMenuOption
->Skip
;
3579 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
3581 if (TopOfScreen
== &gMenuOption
) {
3582 TopOfScreen
= gMenuOption
.ForwardLink
;
3583 NewPos
= gMenuOption
.BackLink
;
3584 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3586 } else if (TopOfScreen
!= Link
) {
3589 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3592 // Finally we know that NewPos is the last MenuOption can be focused.
3596 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3599 if (Index
>= TopRow
) {
3601 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
3603 SkipValue
= PreviousMenuOption
->Skip
- (Index
- TopRow
);
3605 SkipValue
= PreviousMenuOption
->Skip
- (TopRow
- Index
);
3606 Link
= Link
->ForwardLink
;
3610 // Move to the option in Next page.
3612 if (TopOfScreen
== &gMenuOption
) {
3613 NewPos
= gMenuOption
.BackLink
;
3614 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3617 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3621 // There are more MenuOption needing scrolling up.
3628 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3629 // Don't do this when we are already in the first page.
3631 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3632 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3637 // SkipValue means lines is skipped when show the top menu option.
3639 ControlFlag
= CfCheckSelection
;
3641 ASSERT (NewPos
!= NULL
);
3642 if (NewPos
->ForwardLink
== &gMenuOption
) {
3651 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3652 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
3654 // Count to the menu option which will show at the top of the next form.
3656 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
3657 Link
= Link
->ForwardLink
;
3658 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3659 Index
= Index
+ NextMenuOption
->Skip
;
3662 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
3664 // Finally we know that NewPos is the last MenuOption can be focused.
3667 MoveToNextStatement (Selection
, TRUE
, &Link
, Index
- TopRow
);
3671 // Calculate the skip line for top of screen menu.
3673 if (Link
== TopOfScreen
) {
3675 // The top of screen menu option occupies the entire form.
3677 SkipValue
+= BottomRow
- TopRow
+ 1;
3679 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3685 // Move to the Next selectable menu.
3687 MoveToNextStatement (Selection
, FALSE
, &Link
, BottomRow
- TopRow
);
3691 // Save the menu as the next highlight menu.
3696 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3697 // Don't do this when we are already in the last page.
3699 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3700 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3705 // SkipValue means lines is skipped when show the top menu option.
3706 // NewPos points to the menu which is highlighted now.
3708 ControlFlag
= CfCheckSelection
;
3710 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3711 // to be one that progresses to the next set of op-codes, we need to advance to the last
3712 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3713 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3714 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3715 // the Date/Time op-code.
3717 SavedListEntry
= NewPos
;
3718 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3720 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3721 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3723 NewPos
= NewPos
->ForwardLink
;
3727 // Current menu not at the bottom of the form.
3729 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3731 // Find the next selectable menu.
3733 Difference
= MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3735 // We hit the end of MenuOption that can be focused
3736 // so we simply scroll to the first page.
3738 if (Difference
< 0) {
3740 // Scroll to the first page.
3742 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3743 TopOfScreen
= gMenuOption
.ForwardLink
;
3747 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3749 NewPos
= gMenuOption
.ForwardLink
;
3750 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3754 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3756 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3757 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3761 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3762 if (NextMenuOption
->Row
== 0) {
3763 UpdateOptionSkipLines (Selection
, NextMenuOption
);
3765 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3767 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3768 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3769 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3770 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3776 // If we are going to scroll, update TopOfScreen
3778 if (Temp
> BottomRow
) {
3781 // Is the current top of screen a zero-advance op-code?
3782 // If so, keep moving forward till we hit a >0 advance op-code
3784 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3787 // If bottom op-code is more than one line or top op-code is more than one line
3789 if ((DistanceValue
> 1) || (SavedMenuOption
->Skip
> 1)) {
3791 // Is the bottom op-code greater than or equal in size to the top op-code?
3793 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3795 // Skip the top op-code
3797 TopOfScreen
= TopOfScreen
->ForwardLink
;
3798 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3800 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3803 // If we have a remainder, skip that many more op-codes until we drain the remainder
3805 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3807 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3809 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3810 TopOfScreen
= TopOfScreen
->ForwardLink
;
3811 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3814 // Since we will act on this op-code in the next routine, and increment the
3815 // SkipValue, set the skips to one less than what is required.
3817 SkipValue
= Difference
- 1;
3820 // Since we will act on this op-code in the next routine, and increment the
3821 // SkipValue, set the skips to one less than what is required.
3823 SkipValue
+= (Temp
- BottomRow
) - 1;
3826 if ((SkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3827 TopOfScreen
= TopOfScreen
->ForwardLink
;
3832 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3833 // Let's set a skip flag to smoothly scroll the top of the screen.
3835 if (SavedMenuOption
->Skip
> 1) {
3836 if (SavedMenuOption
== NextMenuOption
) {
3841 } else if (SavedMenuOption
->Skip
== 1) {
3845 TopOfScreen
= TopOfScreen
->ForwardLink
;
3847 } while (SavedMenuOption
->Skip
== 0);
3850 } else if (!IsSelectable (NextMenuOption
)) {
3852 // Continue to go down until scroll to next page or the selectable option is found.
3854 ScreenOperation
= UiDown
;
3855 ControlFlag
= CfScreenOperation
;
3858 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3860 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3864 // Scroll to the first page.
3866 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3867 TopOfScreen
= gMenuOption
.ForwardLink
;
3872 // Need to remove the current highlight menu.
3873 // MenuOption saved the last highlight menu info.
3875 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3881 // Get the next highlight menu.
3883 NewPos
= gMenuOption
.ForwardLink
;
3884 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3888 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3890 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3891 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3895 ControlFlag
= CfCheckSelection
;
3897 Status
= EFI_SUCCESS
;
3899 // Discard changes. After it, no NV flag is showed.
3901 if ((HotKey
->Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
3902 Status
= DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3903 if (!EFI_ERROR (Status
)) {
3904 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3905 Selection
->Statement
= NULL
;
3906 gResetRequired
= FALSE
;
3909 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDiscardFailed
, gPressEnter
, gEmptyString
);
3910 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3912 // Still show current page.
3914 Selection
->Action
= UI_ACTION_NONE
;
3922 // Reterieve default setting. After it. NV flag will be showed.
3924 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3925 Status
= ExtractDefault (Selection
->FormSet
, Selection
->Form
, HotKey
->DefaultId
, gBrowserSettingScope
, GetDefaultForAll
, NULL
, FALSE
);
3926 if (!EFI_ERROR (Status
)) {
3927 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3928 Selection
->Statement
= NULL
;
3929 gResetRequired
= TRUE
;
3932 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDefaultFailed
, gPressEnter
, gEmptyString
);
3933 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3935 // Still show current page.
3937 Selection
->Action
= UI_ACTION_NONE
;
3945 // Save changes. After it, no NV flag is showed.
3947 if ((HotKey
->Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
3948 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3949 if (!EFI_ERROR (Status
)) {
3950 ASSERT(MenuOption
!= NULL
);
3951 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3952 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3955 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3956 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3958 // Still show current page.
3960 Selection
->Action
= UI_ACTION_NONE
;
3968 // Set Reset required Flag
3970 if ((HotKey
->Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
3971 gResetRequired
= TRUE
;
3977 if ((HotKey
->Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
3979 // Form Exit without saving, Similar to ESC Key.
3980 // FormSet Exit without saving, Exit SendForm.
3981 // System Exit without saving, CallExitHandler and Exit SendForm.
3983 DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3984 if (gBrowserSettingScope
== FormLevel
) {
3985 ControlFlag
= CfUiReset
;
3986 } else if (gBrowserSettingScope
== FormSetLevel
) {
3987 Selection
->Action
= UI_ACTION_EXIT
;
3988 } else if (gBrowserSettingScope
== SystemLevel
) {
3989 if (ExitHandlerFunction
!= NULL
) {
3990 ExitHandlerFunction ();
3992 Selection
->Action
= UI_ACTION_EXIT
;
3994 Selection
->Statement
= NULL
;
3999 ControlFlag
= CfCheckSelection
;
4001 // Reset to default value for all forms in the whole system.
4003 Status
= ExtractDefault (Selection
->FormSet
, NULL
, DefaultId
, FormSetLevel
, GetDefaultForAll
, NULL
, FALSE
);
4005 if (!EFI_ERROR (Status
)) {
4006 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
4007 Selection
->Statement
= NULL
;
4008 gResetRequired
= TRUE
;
4012 case CfUiNoOperation
:
4013 ControlFlag
= CfCheckSelection
;
4017 UiFreeRefreshList ();
4019 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
4020 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
4021 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
4022 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");
4023 if (HelpString
!= NULL
) {
4024 FreePool (HelpString
);
4026 if (HelpHeaderString
!= NULL
) {
4027 FreePool (HelpHeaderString
);
4029 if (HelpBottomString
!= NULL
) {
4030 FreePool (HelpBottomString
);