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
, FALSE
);
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
;
772 MenuOption
->IsQuestion
= FALSE
;
776 if ((Statement
->ValueExpression
!= NULL
) ||
777 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
778 MenuOption
->ReadOnly
= TRUE
;
781 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
789 Routine used to abstract a generic dialog interface and return the selected key or string
791 @param NumberOfLines The number of lines for the dialog box
792 @param HotKey Defines whether a single character is parsed
793 (TRUE) and returned in KeyValue or a string is
794 returned in StringBuffer. Two special characters
795 are considered when entering a string, a SCAN_ESC
796 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
797 string input and returns
798 @param MaximumStringSize The maximum size in bytes of a typed in string
799 (each character is a CHAR16) and the minimum
800 string returned is two bytes
801 @param StringBuffer The passed in pointer to the buffer which will
802 hold the typed in string if HotKey is FALSE
803 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
804 @param ... A series of (quantity == NumberOfLines) text
805 strings which will be used to construct the dialog
808 @retval EFI_SUCCESS Displayed dialog and received user interaction
809 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
810 (StringBuffer == NULL) && (HotKey == FALSE))
811 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
817 IN UINTN NumberOfLines
,
819 IN UINTN MaximumStringSize
,
820 OUT CHAR16
*StringBuffer
,
821 OUT EFI_INPUT_KEY
*KeyValue
,
830 CHAR16
*BufferedString
;
837 BOOLEAN SelectionComplete
;
839 UINTN CurrentAttribute
;
840 UINTN DimensionsWidth
;
841 UINTN DimensionsHeight
;
843 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
844 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
846 SelectionComplete
= FALSE
;
848 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
849 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
850 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
853 ASSERT (BufferedString
);
856 // Zero the outgoing buffer
858 ZeroMem (StringBuffer
, MaximumStringSize
);
861 if (KeyValue
== NULL
) {
862 return EFI_INVALID_PARAMETER
;
865 if (StringBuffer
== NULL
) {
866 return EFI_INVALID_PARAMETER
;
872 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
876 VA_START (Marker
, KeyValue
);
879 // Determine the largest string in the dialog box
880 // Notice we are starting with 1 since String is the first string
882 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
883 StackString
= VA_ARG (Marker
, CHAR16
*);
885 if (StackString
[0] == L
' ') {
886 InputOffset
= Count
+ 1;
889 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
891 // Size of the string visually and subtract the width by one for the null-terminator
893 LargestString
= (GetStringWidth (StackString
) / 2);
898 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
899 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
906 VA_START (Marker
, KeyValue
);
907 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
911 // Take the first key typed and report it back?
914 Status
= WaitForKeyStroke (&Key
);
915 ASSERT_EFI_ERROR (Status
);
916 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
920 Status
= WaitForKeyStroke (&Key
);
922 switch (Key
.UnicodeChar
) {
924 switch (Key
.ScanCode
) {
926 FreePool (TempString
);
927 FreePool (BufferedString
);
928 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
929 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
930 return EFI_DEVICE_ERROR
;
938 case CHAR_CARRIAGE_RETURN
:
939 SelectionComplete
= TRUE
;
940 FreePool (TempString
);
941 FreePool (BufferedString
);
942 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
943 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
948 if (StringBuffer
[0] != CHAR_NULL
) {
949 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
950 TempString
[Index
] = StringBuffer
[Index
];
953 // Effectively truncate string by 1 character
955 TempString
[Index
- 1] = CHAR_NULL
;
956 StrCpy (StringBuffer
, TempString
);
961 // If it is the beginning of the string, don't worry about checking maximum limits
963 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
964 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
965 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
966 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
967 KeyPad
[0] = Key
.UnicodeChar
;
968 KeyPad
[1] = CHAR_NULL
;
969 StrCat (StringBuffer
, KeyPad
);
970 StrCat (TempString
, KeyPad
);
973 // If the width of the input string is now larger than the screen, we nee to
974 // adjust the index to start printing portions of the string
976 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
978 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
980 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
981 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
986 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
987 BufferedString
[Count
] = StringBuffer
[Index
];
990 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
993 } while (!SelectionComplete
);
996 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
997 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
1002 Draw a pop up windows based on the dimension, number of lines and
1005 @param RequestedWidth The width of the pop-up.
1006 @param NumberOfLines The number of lines.
1007 @param Marker The variable argument list for the list of string to be printed.
1012 IN UINTN RequestedWidth
,
1013 IN UINTN NumberOfLines
,
1025 UINTN DimensionsWidth
;
1026 UINTN DimensionsHeight
;
1028 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1029 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
1031 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1033 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
1034 RequestedWidth
= DimensionsWidth
- 2;
1038 // Subtract the PopUp width from total Columns, allow for one space extra on
1039 // each end plus a border.
1041 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
1042 End
= Start
+ RequestedWidth
+ 1;
1044 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
1045 Bottom
= Top
+ NumberOfLines
+ 2;
1047 Character
= BOXDRAW_DOWN_RIGHT
;
1048 PrintCharAt (Start
, Top
, Character
);
1049 Character
= BOXDRAW_HORIZONTAL
;
1050 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1051 PrintChar (Character
);
1054 Character
= BOXDRAW_DOWN_LEFT
;
1055 PrintChar (Character
);
1056 Character
= BOXDRAW_VERTICAL
;
1059 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
1060 String
= VA_ARG (Marker
, CHAR16
*);
1063 // This will clear the background of the line - we never know who might have been
1064 // here before us. This differs from the next clear in that it used the non-reverse
1065 // video for normal printing.
1067 if (GetStringWidth (String
) / 2 > 1) {
1068 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
1072 // Passing in a space results in the assumption that this is where typing will occur
1074 if (String
[0] == L
' ') {
1075 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
1079 // Passing in a NULL results in a blank space
1081 if (String
[0] == CHAR_NULL
) {
1082 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
1086 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
1090 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1091 PrintCharAt (Start
, Index
+ 1, Character
);
1092 PrintCharAt (End
- 1, Index
+ 1, Character
);
1095 Character
= BOXDRAW_UP_RIGHT
;
1096 PrintCharAt (Start
, Bottom
- 1, Character
);
1097 Character
= BOXDRAW_HORIZONTAL
;
1098 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1099 PrintChar (Character
);
1102 Character
= BOXDRAW_UP_LEFT
;
1103 PrintChar (Character
);
1107 Draw a pop up windows based on the dimension, number of lines and
1110 @param RequestedWidth The width of the pop-up.
1111 @param NumberOfLines The number of lines.
1112 @param ... A series of text strings that displayed in the pop-up.
1117 CreateMultiStringPopUp (
1118 IN UINTN RequestedWidth
,
1119 IN UINTN NumberOfLines
,
1125 VA_START (Marker
, NumberOfLines
);
1127 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1134 Update status bar on the bottom of menu.
1136 @param Selection Current Selction info.
1137 @param MessageType The type of message to be shown.
1138 @param Flags The flags in Question header.
1139 @param State Set or clear.
1144 IN UI_MENU_SELECTION
*Selection
,
1145 IN UINTN MessageType
,
1151 CHAR16
*NvUpdateMessage
;
1152 CHAR16
*InputErrorMessage
;
1154 FORM_BROWSER_FORMSET
*LocalFormSet
;
1155 FORM_BROWSER_STATEMENT
*Question
;
1157 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1158 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1160 switch (MessageType
) {
1163 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1165 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1166 gScreenDimensions
.BottomRow
- 1,
1171 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1172 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1173 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1176 mInputError
= FALSE
;
1180 case NV_UPDATE_REQUIRED
:
1182 // Global setting support. Show configuration change on every form.
1185 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1187 if (Selection
!= NULL
&& Selection
->Statement
!= NULL
) {
1188 Question
= Selection
->Statement
;
1189 if (Question
->Storage
!= NULL
|| Question
->Operand
== EFI_IFR_DATE_OP
|| Question
->Operand
== EFI_IFR_TIME_OP
) {
1191 // Update only for Question value that need to be saved into Storage.
1193 Selection
->Form
->NvUpdateRequired
= TRUE
;
1197 if (Selection
== NULL
|| IsNvUpdateRequired (Selection
->FormSet
)) {
1198 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1200 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1201 gScreenDimensions
.BottomRow
- 1,
1206 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1207 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1209 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1210 gScreenDimensions
.BottomRow
- 1,
1217 case REFRESH_STATUS_BAR
:
1219 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1222 switch (gBrowserSettingScope
) {
1225 // Check the maintain list to see whether there is any change.
1227 Link
= GetFirstNode (&gBrowserFormSetList
);
1228 while (!IsNull (&gBrowserFormSetList
, Link
)) {
1229 LocalFormSet
= FORM_BROWSER_FORMSET_FROM_LINK (Link
);
1230 if (IsNvUpdateRequired(LocalFormSet
)) {
1231 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1234 Link
= GetNextNode (&gBrowserFormSetList
, Link
);
1239 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1250 FreePool (InputErrorMessage
);
1251 FreePool (NvUpdateMessage
);
1257 Get the supported width for a particular op-code
1259 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1260 @param Handle The handle in the HII database being used
1262 @return Returns the number of CHAR16 characters that is support.
1267 IN FORM_BROWSER_STATEMENT
*Statement
,
1268 IN EFI_HII_HANDLE Handle
1278 // See if the second text parameter is really NULL
1280 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1281 String
= GetToken (Statement
->TextTwo
, Handle
);
1282 Size
= StrLen (String
);
1286 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1287 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1288 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1289 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1290 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1292 // Allow a wide display if text op-code and no secondary text op-code
1294 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1296 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1298 Width
= (UINT16
) gPromptBlockWidth
;
1301 if (Statement
->InSubtitle
) {
1302 Width
-= SUBTITLE_INDENT
;
1305 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1309 Will copy LineWidth amount of a string in the OutputString buffer and return the
1310 number of CHAR16 characters that were copied into the OutputString buffer.
1311 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
1313 @param InputString String description for this option.
1314 @param LineWidth Width of the desired string to extract in CHAR16
1316 @param Index Where in InputString to start the copy process
1317 @param OutputString Buffer to copy the string into
1319 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1324 IN CHAR16
*InputString
,
1325 IN UINT16 LineWidth
,
1326 IN OUT UINTN
*Index
,
1327 OUT CHAR16
**OutputString
1333 if (GetLineByWidthFinished
) {
1334 GetLineByWidthFinished
= FALSE
;
1341 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1344 // Ensure we have got a valid buffer
1346 if (*OutputString
!= NULL
) {
1349 //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.
1350 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1352 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1353 *Index
= *Index
+ 2;
1357 // Fast-forward the string and see if there is a carriage-return or linefeed in the string
1359 for (; (InputString
[*Index
+ Count2
] != CHAR_LINEFEED
) && (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1363 // Copy the desired LineWidth of data to the output buffer.
1364 // Also make sure that we don't copy more than the string.
1365 // Also make sure that if there are linefeeds, we account for them.
1367 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1368 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1371 // Convert to CHAR16 value and show that we are done with this operation
1373 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1374 if (LineWidth
!= 0) {
1375 GetLineByWidthFinished
= TRUE
;
1378 if (Count2
== LineWidth
) {
1380 // Rewind the string from the maximum size until we see a space to break the line
1382 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1384 if (LineWidth
== 0) {
1392 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1395 // If currently pointing to a space or carriage-return or linefeed, increment the index to the first non-space character
1398 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
)|| (InputString
[*Index
+ LineWidth
] == CHAR_LINEFEED
);
1402 *Index
= (UINT16
) (*Index
+ LineWidth
);
1411 Update display lines for a Menu Option.
1413 @param Selection The user's selection.
1414 @param MenuOption The MenuOption to be checked.
1418 UpdateOptionSkipLines (
1419 IN UI_MENU_SELECTION
*Selection
,
1420 IN UI_MENU_OPTION
*MenuOption
1427 CHAR16
*OutputString
;
1428 CHAR16
*OptionString
;
1431 OptionString
= NULL
;
1432 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1434 if (OptionString
!= NULL
) {
1435 Width
= (UINT16
) gOptionBlockWidth
;
1439 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1441 // If there is more string to process print on the next row and increment the Skip value
1443 if (StrLen (&OptionString
[Index
]) != 0) {
1446 // Since the Number of lines for this menu entry may or may not be reflected accurately
1447 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1448 // some testing to ensure we are keeping this in-sync.
1450 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1452 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1457 FreePool (OutputString
);
1463 if (OptionString
!= NULL
) {
1464 FreePool (OptionString
);
1470 Check whether this Menu Option could be highlighted.
1472 This is an internal function.
1474 @param MenuOption The MenuOption to be checked.
1476 @retval TRUE This Menu Option is selectable.
1477 @retval FALSE This Menu Option could not be selected.
1482 UI_MENU_OPTION
*MenuOption
1485 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1486 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1495 Determine if the menu is the last menu that can be selected.
1497 This is an internal function.
1499 @param Direction The scroll direction. False is down. True is up.
1500 @param CurrentPos The current focus.
1502 @return FALSE -- the menu isn't the last menu that can be selected.
1503 @return TRUE -- the menu is the last menu that can be selected.
1508 IN BOOLEAN Direction
,
1509 IN LIST_ENTRY
*CurrentPos
1514 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1516 if (Temp
== &gMenuOption
) {
1525 Move to next selectable statement.
1527 This is an internal function.
1529 @param Selection Menu selection.
1530 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1531 @param CurrentPosition Current position.
1532 @param GapToTop Gap position to top or bottom.
1534 @return The row distance from current MenuOption to next selectable MenuOption.
1538 MoveToNextStatement (
1539 IN UI_MENU_SELECTION
*Selection
,
1541 IN OUT LIST_ENTRY
**CurrentPosition
,
1547 UI_MENU_OPTION
*NextMenuOption
;
1548 UI_MENU_OPTION
*PreMenuOption
;
1551 Pos
= *CurrentPosition
;
1552 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1555 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1556 if (NextMenuOption
->Row
== 0) {
1557 UpdateOptionSkipLines (Selection
, NextMenuOption
);
1560 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1562 // Current Position doesn't need to be caculated when go up.
1563 // Caculate distanct at first when go up
1565 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1566 NextMenuOption
= PreMenuOption
;
1569 Distance
+= NextMenuOption
->Skip
;
1571 if (IsSelectable (NextMenuOption
)) {
1574 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1583 // Caculate distanct at later when go down
1585 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1586 NextMenuOption
= PreMenuOption
;
1589 Distance
+= NextMenuOption
->Skip
;
1591 PreMenuOption
= NextMenuOption
;
1592 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1595 *CurrentPosition
= &NextMenuOption
->Link
;
1601 Adjust Data and Time position accordingly.
1602 Data format : [01/02/2004] [11:22:33]
1603 Line number : 0 0 1 0 0 1
1605 This is an internal function.
1607 @param DirectionUp the up or down direction. False is down. True is
1609 @param CurrentPosition Current position. On return: Point to the last
1610 Option (Year or Second) if up; Point to the first
1611 Option (Month or Hour) if down.
1613 @return Return line number to pad. It is possible that we stand on a zero-advance
1614 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1618 AdjustDateAndTimePosition (
1619 IN BOOLEAN DirectionUp
,
1620 IN OUT LIST_ENTRY
**CurrentPosition
1624 LIST_ENTRY
*NewPosition
;
1625 UI_MENU_OPTION
*MenuOption
;
1626 UINTN PadLineNumber
;
1629 NewPosition
= *CurrentPosition
;
1630 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1632 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1633 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1635 // Calculate the distance from current position to the last Date/Time MenuOption
1638 while (MenuOption
->Skip
== 0) {
1640 NewPosition
= NewPosition
->ForwardLink
;
1641 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1645 NewPosition
= *CurrentPosition
;
1648 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1649 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1650 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1651 // checking can be done.
1653 while (Count
++ < 2) {
1654 NewPosition
= NewPosition
->BackLink
;
1658 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1659 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1660 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1661 // checking can be done.
1663 while (Count
-- > 0) {
1664 NewPosition
= NewPosition
->ForwardLink
;
1668 *CurrentPosition
= NewPosition
;
1671 return PadLineNumber
;
1675 Find HII Handle in the HII database associated with given Device Path.
1677 If DevicePath is NULL, then ASSERT.
1679 @param DevicePath Device Path associated with the HII package list
1682 @retval Handle HII package list Handle associated with the Device
1684 @retval NULL Hii Package list handle is not found.
1689 DevicePathToHiiHandle (
1690 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1694 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1699 EFI_HANDLE DriverHandle
;
1700 EFI_HII_HANDLE
*HiiHandles
;
1701 EFI_HII_HANDLE HiiHandle
;
1703 ASSERT (DevicePath
!= NULL
);
1705 TmpDevicePath
= DevicePath
;
1707 // Locate Device Path Protocol handle buffer
1709 Status
= gBS
->LocateDevicePath (
1710 &gEfiDevicePathProtocolGuid
,
1714 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1719 // Retrieve all HII Handles from HII database
1721 BufferSize
= 0x1000;
1722 HiiHandles
= AllocatePool (BufferSize
);
1723 ASSERT (HiiHandles
!= NULL
);
1724 Status
= mHiiDatabase
->ListPackageLists (
1726 EFI_HII_PACKAGE_TYPE_ALL
,
1731 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1732 FreePool (HiiHandles
);
1733 HiiHandles
= AllocatePool (BufferSize
);
1734 ASSERT (HiiHandles
!= NULL
);
1736 Status
= mHiiDatabase
->ListPackageLists (
1738 EFI_HII_PACKAGE_TYPE_ALL
,
1745 if (EFI_ERROR (Status
)) {
1746 FreePool (HiiHandles
);
1751 // Search Hii Handle by Driver Handle
1754 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1755 for (Index
= 0; Index
< HandleCount
; Index
++) {
1756 Status
= mHiiDatabase
->GetPackageListHandle (
1761 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1762 HiiHandle
= HiiHandles
[Index
];
1767 FreePool (HiiHandles
);
1772 Find HII Handle in the HII database associated with given form set guid.
1774 If FormSetGuid is NULL, then ASSERT.
1776 @param ComparingGuid FormSet Guid associated with the HII package list
1779 @retval Handle HII package list Handle associated with the Device
1781 @retval NULL Hii Package list handle is not found.
1785 FormSetGuidToHiiHandle (
1786 EFI_GUID
*ComparingGuid
1789 EFI_HII_HANDLE
*HiiHandles
;
1791 EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
;
1795 UINT32 PackageListLength
;
1796 EFI_HII_PACKAGE_HEADER PackageHeader
;
1800 EFI_HII_HANDLE HiiHandle
;
1802 ASSERT (ComparingGuid
!= NULL
);
1806 // Get all the Hii handles
1808 HiiHandles
= HiiGetHiiHandles (NULL
);
1809 ASSERT (HiiHandles
!= NULL
);
1812 // Search for formset of each class type
1814 for (Index
= 0; HiiHandles
[Index
] != NULL
; Index
++) {
1816 HiiPackageList
= NULL
;
1817 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1818 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1819 HiiPackageList
= AllocatePool (BufferSize
);
1820 ASSERT (HiiPackageList
!= NULL
);
1822 Status
= mHiiDatabase
->ExportPackageLists (mHiiDatabase
, HiiHandles
[Index
], &BufferSize
, HiiPackageList
);
1824 if (EFI_ERROR (Status
) || HiiPackageList
== NULL
) {
1829 // Get Form package from this HII package List
1831 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
1833 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
1835 while (Offset
< PackageListLength
) {
1836 Package
= ((UINT8
*) HiiPackageList
) + Offset
;
1837 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
1839 if (PackageHeader
.Type
== EFI_HII_PACKAGE_FORMS
) {
1841 // Search FormSet in this Form Package
1843 Offset2
= sizeof (EFI_HII_PACKAGE_HEADER
);
1844 while (Offset2
< PackageHeader
.Length
) {
1845 OpCodeData
= Package
+ Offset2
;
1847 if (((EFI_IFR_OP_HEADER
*) OpCodeData
)->OpCode
== EFI_IFR_FORM_SET_OP
) {
1849 // Try to compare against formset GUID
1851 if (CompareGuid (ComparingGuid
, (EFI_GUID
*)(OpCodeData
+ sizeof (EFI_IFR_OP_HEADER
)))) {
1852 HiiHandle
= HiiHandles
[Index
];
1857 Offset2
+= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
1860 if (HiiHandle
!= NULL
) {
1863 Offset
+= PackageHeader
.Length
;
1866 FreePool (HiiPackageList
);
1867 if (HiiHandle
!= NULL
) {
1872 FreePool (HiiHandles
);
1878 Process the goto op code, update the info in the selection structure.
1880 @param Statement The statement belong to goto op code.
1881 @param Selection The selection info.
1882 @param Repaint Whether need to repaint the menu.
1883 @param NewLine Whether need to create new line.
1885 @retval EFI_SUCCESS The menu process successfully.
1886 @return Other value if the process failed.
1890 IN OUT FORM_BROWSER_STATEMENT
*Statement
,
1891 IN OUT UI_MENU_SELECTION
*Selection
,
1892 OUT BOOLEAN
*Repaint
,
1893 OUT BOOLEAN
*NewLine
1899 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1901 UINT8
*DevicePathBuffer
;
1904 FORM_BROWSER_FORM
*RefForm
;
1907 UI_MENU_LIST
*MenuList
;
1908 BOOLEAN UpdateFormInfo
;
1910 Status
= EFI_SUCCESS
;
1911 UpdateFormInfo
= TRUE
;
1916 // Prepare the device path check, get the device path info first.
1918 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0) {
1919 StringPtr
= GetToken (Statement
->HiiValue
.Value
.ref
.DevicePath
, Selection
->FormSet
->HiiHandle
);
1920 if (StringPtr
!= NULL
) {
1921 StringLen
= StrLen (StringPtr
);
1926 // Check whether the device path string is a valid string.
1928 if (Statement
->HiiValue
.Value
.ref
.DevicePath
!= 0 && StringPtr
!= NULL
&& StringLen
!= 0) {
1929 if (Selection
->Form
->ModalForm
) {
1933 // Goto another Hii Package list
1935 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1936 BufferSize
= StrLen (StringPtr
) / 2;
1937 DevicePath
= AllocatePool (BufferSize
);
1938 ASSERT (DevicePath
!= NULL
);
1941 // Convert from Device Path String to DevicePath Buffer in the reverse order.
1943 DevicePathBuffer
= (UINT8
*) DevicePath
;
1944 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
1945 TemStr
[0] = StringPtr
[Index
];
1946 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
1947 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
1949 // Invalid Hex Char as the tail.
1953 if ((Index
& 1) == 0) {
1954 DevicePathBuffer
[Index
/2] = DigitUint8
;
1956 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
1959 FreePool (StringPtr
);
1961 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
1962 FreePool (DevicePath
);
1964 if (Selection
->Handle
== NULL
) {
1966 // If target Hii Handle not found, exit
1968 Selection
->Action
= UI_ACTION_EXIT
;
1969 Selection
->Statement
= NULL
;
1973 CopyMem (&Selection
->FormSetGuid
,&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1974 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1975 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1976 } else if (!CompareGuid (&Statement
->HiiValue
.Value
.ref
.FormSetGuid
, &gZeroGuid
)) {
1977 if (Selection
->Form
->ModalForm
) {
1981 // Goto another Formset, check for uncommitted data
1983 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
1985 Selection
->Handle
= FormSetGuidToHiiHandle(&Statement
->HiiValue
.Value
.ref
.FormSetGuid
);
1986 if (Selection
->Handle
== NULL
) {
1988 // If target Hii Handle not found, exit
1990 Selection
->Action
= UI_ACTION_EXIT
;
1991 Selection
->Statement
= NULL
;
1995 CopyMem (&Selection
->FormSetGuid
, &Statement
->HiiValue
.Value
.ref
.FormSetGuid
, sizeof (EFI_GUID
));
1996 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
1997 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
1998 } else if (Statement
->HiiValue
.Value
.ref
.FormId
!= 0) {
2000 // Check whether target From is suppressed.
2002 RefForm
= IdToForm (Selection
->FormSet
, Statement
->HiiValue
.Value
.ref
.FormId
);
2004 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2005 if (EvaluateExpressionList(RefForm
->SuppressExpression
, TRUE
, Selection
->FormSet
, RefForm
) != ExpressFalse
) {
2007 // Form is suppressed.
2010 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2011 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2012 if (Repaint
!= NULL
) {
2020 // Goto another form inside this formset,
2022 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2024 Selection
->FormId
= Statement
->HiiValue
.Value
.ref
.FormId
;
2025 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2026 } else if (Statement
->HiiValue
.Value
.ref
.QuestionId
!= 0) {
2028 // Goto another Question
2030 Selection
->QuestionId
= Statement
->HiiValue
.Value
.ref
.QuestionId
;
2032 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2033 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2035 if (Repaint
!= NULL
) {
2038 if (NewLine
!= NULL
) {
2042 UpdateFormInfo
= FALSE
;
2044 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2045 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2047 UpdateFormInfo
= FALSE
;
2050 if (UpdateFormInfo
) {
2052 // Link current form so that we can always go back when someone hits the ESC
2054 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
2055 if (MenuList
== NULL
&& Selection
->CurrentMenu
!= NULL
) {
2056 MenuList
= UiAddMenuList (Selection
->CurrentMenu
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
2064 Display menu and wait for user to select one menu option, then return it.
2065 If AutoBoot is enabled, then if user doesn't select any option,
2066 after period of time, it will automatically return the first menu option.
2068 @param Selection Menu selection.
2070 @retval EFI_SUCESSS This function always return successfully for now.
2075 IN OUT UI_MENU_SELECTION
*Selection
2081 UINTN DistanceValue
;
2092 CHAR16
*OptionString
;
2093 CHAR16
*OutputString
;
2095 CHAR16
*HelpHeaderString
;
2096 CHAR16
*HelpBottomString
;
2102 BOOLEAN InitializedFlag
;
2107 LIST_ENTRY
*TopOfScreen
;
2108 LIST_ENTRY
*SavedListEntry
;
2109 UI_MENU_OPTION
*MenuOption
;
2110 UI_MENU_OPTION
*NextMenuOption
;
2111 UI_MENU_OPTION
*SavedMenuOption
;
2112 UI_MENU_OPTION
*PreviousMenuOption
;
2113 UI_CONTROL_FLAG ControlFlag
;
2114 EFI_SCREEN_DESCRIPTOR LocalScreen
;
2115 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
2116 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
2117 UI_SCREEN_OPERATION ScreenOperation
;
2118 UINT8 MinRefreshInterval
;
2120 FORM_BROWSER_STATEMENT
*Statement
;
2121 UI_MENU_LIST
*CurrentMenu
;
2122 UINTN ModalSkipColumn
;
2123 BROWSER_HOT_KEY
*HotKey
;
2124 UINTN HelpPageIndex
;
2125 UINTN HelpPageCount
;
2128 UINTN HelpHeaderLine
;
2129 UINTN HelpBottomLine
;
2130 BOOLEAN MultiHelpPage
;
2132 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
2134 Status
= EFI_SUCCESS
;
2136 HelpHeaderString
= NULL
;
2137 HelpBottomString
= NULL
;
2138 OptionString
= NULL
;
2139 ScreenOperation
= UiNoOperation
;
2141 MinRefreshInterval
= 0;
2149 MultiHelpPage
= FALSE
;
2151 OutputString
= NULL
;
2156 MenuRefreshEntry
= gMenuRefreshHead
;
2158 NextMenuOption
= NULL
;
2159 PreviousMenuOption
= NULL
;
2160 SavedMenuOption
= NULL
;
2162 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
2164 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2166 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
2167 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2168 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2170 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2171 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
2174 if (Selection
->Form
->ModalForm
) {
2175 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
2177 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2180 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- gFooterHeight
- SCROLL_ARROW_HEIGHT
- 1;
2182 Selection
->TopRow
= TopRow
;
2183 Selection
->BottomRow
= BottomRow
;
2184 Selection
->PromptCol
= Col
;
2185 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2186 Selection
->Statement
= NULL
;
2188 TopOfScreen
= gMenuOption
.ForwardLink
;
2193 // Find current Menu
2195 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
2196 if (CurrentMenu
== NULL
) {
2198 // Current menu not found, add it to the menu tree
2200 CurrentMenu
= UiAddMenuList (NULL
, Selection
->Handle
, &Selection
->FormSetGuid
, Selection
->FormId
);
2202 ASSERT (CurrentMenu
!= NULL
);
2203 Selection
->CurrentMenu
= CurrentMenu
;
2205 if (Selection
->QuestionId
== 0) {
2207 // Highlight not specified, fetch it from cached menu
2209 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
2210 Selection
->Sequence
= CurrentMenu
->Sequence
;
2214 // Init option as the current user's selection
2216 InitializedFlag
= TRUE
;
2217 NewPos
= gMenuOption
.ForwardLink
;
2219 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2220 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
2222 ControlFlag
= CfInitialization
;
2223 Selection
->Action
= UI_ACTION_NONE
;
2225 switch (ControlFlag
) {
2226 case CfInitialization
:
2227 if (IsListEmpty (&gMenuOption
)) {
2228 ControlFlag
= CfReadKey
;
2230 ControlFlag
= CfCheckSelection
;
2234 case CfCheckSelection
:
2235 if (Selection
->Action
!= UI_ACTION_NONE
) {
2236 ControlFlag
= CfExit
;
2238 ControlFlag
= CfRepaint
;
2243 ControlFlag
= CfRefreshHighLight
;
2253 Temp
= (UINTN
) SkipValue
;
2254 Temp2
= (UINTN
) SkipValue
;
2256 if (Selection
->Form
->ModalForm
) {
2258 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
2259 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
2260 TopRow
- SCROLL_ARROW_HEIGHT
,
2261 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2262 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2266 LocalScreen
.LeftColumn
,
2267 LocalScreen
.RightColumn
,
2268 TopRow
- SCROLL_ARROW_HEIGHT
,
2269 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2270 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2273 UiFreeRefreshList ();
2274 MinRefreshInterval
= 0;
2276 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2277 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2278 MenuOption
->Row
= Row
;
2279 MenuOption
->Col
= Col
;
2280 if (Selection
->Form
->ModalForm
) {
2281 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
2283 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
2286 Statement
= MenuOption
->ThisTag
;
2287 if (Statement
->InSubtitle
) {
2288 MenuOption
->Col
+= SUBTITLE_INDENT
;
2291 if (MenuOption
->GrayOut
) {
2292 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2294 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2295 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2299 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2302 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
2304 // Print Arrow for Goto button.
2307 MenuOption
->Col
- 2,
2310 GEOMETRICSHAPE_RIGHT_TRIANGLE
2314 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2315 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2316 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
2319 // If there is more string to process print on the next row and increment the Skip value
2321 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2327 FreePool (OutputString
);
2336 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2337 if (EFI_ERROR (Status
)) {
2339 // Repaint to clear possible error prompt pop-up
2343 ControlFlag
= CfRepaint
;
2347 if (OptionString
!= NULL
) {
2348 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2349 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
2352 Width
= (UINT16
) gOptionBlockWidth
;
2355 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2356 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2357 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2360 // If there is more string to process print on the next row and increment the Skip value
2362 if (StrLen (&OptionString
[Index
]) != 0) {
2366 // Since the Number of lines for this menu entry may or may not be reflected accurately
2367 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2368 // some testing to ensure we are keeping this in-sync.
2370 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2372 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2378 FreePool (OutputString
);
2387 FreePool (OptionString
);
2391 // If Question has refresh guid, register the op-code.
2393 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
2394 if (gMenuEventGuidRefreshHead
== NULL
) {
2395 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2396 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
2398 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
2399 while (MenuUpdateEntry
->Next
!= NULL
) {
2400 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2402 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2403 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
2405 ASSERT (MenuUpdateEntry
!= NULL
);
2406 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
2407 ASSERT (!EFI_ERROR (Status
));
2408 MenuUpdateEntry
->MenuOption
= MenuOption
;
2409 MenuUpdateEntry
->Selection
= Selection
;
2410 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
2411 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
2412 if (MenuOption
->GrayOut
) {
2413 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2415 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2420 // If Question request refresh, register the op-code
2422 if (Statement
->RefreshInterval
!= 0) {
2424 // Menu will be refreshed at minimal interval of all Questions
2425 // which have refresh request
2427 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
2428 MinRefreshInterval
= Statement
->RefreshInterval
;
2431 if (gMenuRefreshHead
== NULL
) {
2432 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2433 gMenuRefreshHead
= MenuRefreshEntry
;
2435 MenuRefreshEntry
= gMenuRefreshHead
;
2436 while (MenuRefreshEntry
->Next
!= NULL
) {
2437 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2439 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2440 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2442 ASSERT (MenuRefreshEntry
!= NULL
);
2443 MenuRefreshEntry
->MenuOption
= MenuOption
;
2444 MenuRefreshEntry
->Selection
= Selection
;
2445 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2446 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2447 if (MenuOption
->GrayOut
) {
2448 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2450 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2455 // If this is a text op with secondary text information
2457 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2458 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2460 Width
= (UINT16
) gOptionBlockWidth
;
2463 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
2464 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2465 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2468 // If there is more string to process print on the next row and increment the Skip value
2470 if (StrLen (&StringPtr
[Index
]) != 0) {
2474 // Since the Number of lines for this menu entry may or may not be reflected accurately
2475 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2476 // some testing to ensure we are keeping this in-sync.
2478 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2480 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2486 FreePool (OutputString
);
2493 FreePool (StringPtr
);
2495 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2498 // Need to handle the bottom of the display
2500 if (MenuOption
->Skip
> 1) {
2501 Row
+= MenuOption
->Skip
- SkipValue
;
2504 Row
+= MenuOption
->Skip
;
2507 if (Row
> BottomRow
) {
2508 if (!ValueIsScroll (FALSE
, Link
)) {
2512 Row
= BottomRow
+ 1;
2517 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2522 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2524 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2525 TopRow
- SCROLL_ARROW_HEIGHT
,
2529 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2533 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2535 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2536 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2540 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2547 case CfRefreshHighLight
:
2549 // MenuOption: Last menu option that need to remove hilight
2550 // MenuOption is set to NULL in Repaint
2551 // NewPos: Current menu option that need to hilight
2553 ControlFlag
= CfUpdateHelpString
;
2554 if (InitializedFlag
) {
2555 InitializedFlag
= FALSE
;
2556 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
2560 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2561 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2563 SavedValue
= Repaint
;
2566 if (Selection
->QuestionId
!= 0) {
2567 NewPos
= gMenuOption
.ForwardLink
;
2568 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2570 while ((SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
||
2571 SavedMenuOption
->Sequence
!= Selection
->Sequence
) &&
2572 NewPos
->ForwardLink
!= &gMenuOption
) {
2573 NewPos
= NewPos
->ForwardLink
;
2574 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2576 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2578 // Target Question found, find its MenuOption
2582 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2583 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2584 Index
+= SavedMenuOption
->Skip
;
2585 if (Link
== TopOfScreen
) {
2586 Index
-= OldSkipValue
;
2588 Link
= Link
->ForwardLink
;
2590 if (NewPos
== Link
) {
2591 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2595 // Not find the selected menu in current show page.
2596 // Have two case to enter this if:
2597 // 1. Not find the menu at current page.
2598 // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.
2599 // For case 2, has an exception: The menu can show more than one pages and now only this menu shows.
2601 // Base on the selected menu will show at the bottom of the page,
2602 // select the menu which will show at the top of the page.
2604 if (Link
!= NewPos
|| Index
> BottomRow
||
2605 (Link
== NewPos
&& (SavedMenuOption
->Row
+ SavedMenuOption
->Skip
- 1 > BottomRow
) && (Link
!= TopOfScreen
))) {
2607 // Find the MenuOption which has the skip value for Date/Time opcode.
2609 AdjustDateAndTimePosition(FALSE
, &NewPos
);
2611 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2613 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2615 // SavedMenuOption->Row == 0 means the menu not show yet.
2617 if (SavedMenuOption
->Row
== 0) {
2618 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2622 // Base on the selected menu will show at the bottome of next page,
2623 // select the menu show at the top of the next page.
2626 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= BottomRow
+ 1; ) {
2627 Link
= Link
->BackLink
;
2628 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2629 if (SavedMenuOption
->Row
== 0) {
2630 UpdateOptionSkipLines (Selection
, SavedMenuOption
);
2632 Index
+= SavedMenuOption
->Skip
;
2636 // Found the menu which will show at the top of the page.
2638 if (Link
== NewPos
) {
2640 // The menu can show more than one pages, just show the menu at the top of the page.
2644 OldSkipValue
= SkipValue
;
2647 // Check whether need to skip some line for menu shows at the top of the page.
2649 SkipValue
= Index
- BottomRow
- 1;
2650 if (SkipValue
> 0 && SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
2652 OldSkipValue
= SkipValue
;
2655 TopOfScreen
= Link
->ForwardLink
;
2661 ControlFlag
= CfRepaint
;
2666 // Target Question not found, highlight the default menu option
2668 NewPos
= TopOfScreen
;
2671 Selection
->QuestionId
= 0;
2674 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2675 if (MenuOption
!= NULL
) {
2677 // Remove highlight on last Menu Option
2679 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2680 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2681 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2682 if (OptionString
!= NULL
) {
2683 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2684 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2686 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2689 Width
= (UINT16
) gOptionBlockWidth
;
2690 OriginalRow
= MenuOption
->Row
;
2692 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2693 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2694 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2697 // If there is more string to process print on the next row and increment the Skip value
2699 if (StrLen (&OptionString
[Index
]) != 0) {
2703 FreePool (OutputString
);
2706 MenuOption
->Row
= OriginalRow
;
2708 FreePool (OptionString
);
2711 if (MenuOption
->GrayOut
) {
2712 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2713 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2714 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2717 OriginalRow
= MenuOption
->Row
;
2718 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2720 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2721 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2722 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2725 // If there is more string to process print on the next row and increment the Skip value
2727 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2731 FreePool (OutputString
);
2734 MenuOption
->Row
= OriginalRow
;
2735 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2741 // This is the current selected statement
2743 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2744 Statement
= MenuOption
->ThisTag
;
2745 Selection
->Statement
= Statement
;
2746 if (!IsSelectable (MenuOption
)) {
2747 Repaint
= SavedValue
;
2748 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2753 // Record highlight for current menu
2755 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2756 CurrentMenu
->Sequence
= MenuOption
->Sequence
;
2759 // Set reverse attribute
2761 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2762 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2765 // Assuming that we have a refresh linked-list created, lets annotate the
2766 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2767 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2769 if (gMenuRefreshHead
!= NULL
) {
2770 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2771 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2772 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2774 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2776 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2777 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2782 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2783 if (OptionString
!= NULL
) {
2784 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2785 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2787 Width
= (UINT16
) gOptionBlockWidth
;
2789 OriginalRow
= MenuOption
->Row
;
2791 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2792 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2793 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2796 // If there is more string to process print on the next row and increment the Skip value
2798 if (StrLen (&OptionString
[Index
]) != 0) {
2802 FreePool (OutputString
);
2805 MenuOption
->Row
= OriginalRow
;
2807 FreePool (OptionString
);
2810 OriginalRow
= MenuOption
->Row
;
2812 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2814 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2815 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2816 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2819 // If there is more string to process print on the next row and increment the Skip value
2821 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2825 FreePool (OutputString
);
2828 MenuOption
->Row
= OriginalRow
;
2833 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2836 // Clear reverse attribute
2838 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2841 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2842 // if we didn't break halfway when process CfRefreshHighLight.
2844 Repaint
= SavedValue
;
2847 case CfUpdateHelpString
:
2848 ControlFlag
= CfPrepareToReadKey
;
2849 if (Selection
->Form
->ModalForm
) {
2853 if (Repaint
|| NewLine
) {
2855 // Don't print anything if it is a NULL help token
2857 ASSERT(MenuOption
!= NULL
);
2858 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2861 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2864 RowCount
= BottomRow
- TopRow
;
2867 // 1.Calculate how many line the help string need to print.
2869 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, RowCount
);
2870 if (HelpLine
> RowCount
) {
2871 MultiHelpPage
= TRUE
;
2872 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2873 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, RowCount
);
2874 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2875 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, RowCount
);
2877 // Calculate the help page count.
2879 if (HelpLine
> 2 * RowCount
- 2) {
2880 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2881 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
2888 MultiHelpPage
= FALSE
;
2893 // Clean the help field first.
2896 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2897 LocalScreen
.RightColumn
,
2900 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
2903 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
| FIELD_BACKGROUND
);
2905 // Check whether need to show the 'More(U/u)' at the begin.
2906 // Base on current direct info, here shows aligned to the right side of the column.
2907 // If the direction is multi line and aligned to right side may have problem, so
2908 // add ASSERT code here.
2910 if (HelpPageIndex
> 0) {
2911 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2912 ASSERT (HelpHeaderLine
== 1);
2913 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2915 LocalScreen
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2917 &HelpHeaderString
[Index
* gHelpBlockWidth
* 2]
2922 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2924 // Print the help string info.
2926 if (!MultiHelpPage
) {
2927 for (Index
= 0; Index
< HelpLine
; Index
++) {
2929 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2931 &HelpString
[Index
* gHelpBlockWidth
* 2]
2935 if (HelpPageIndex
== 0) {
2936 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
2938 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2940 &HelpString
[Index
* gHelpBlockWidth
* 2]
2944 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
2945 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
2947 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2948 Index
+ TopRow
+ HelpHeaderLine
,
2949 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* gHelpBlockWidth
* 2]
2955 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
| FIELD_BACKGROUND
);
2957 // Check whether need to print the 'More(D/d)' at the bottom.
2958 // Base on current direct info, here shows aligned to the right side of the column.
2959 // If the direction is multi line and aligned to right side may have problem, so
2960 // add ASSERT code here.
2962 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
2963 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
2964 ASSERT (HelpBottomLine
== 1);
2965 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2967 LocalScreen
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
2968 Index
+ BottomRow
- HelpBottomLine
,
2969 &HelpBottomString
[Index
* gHelpBlockWidth
* 2]
2974 // Reset this flag every time we finish using it.
2980 case CfPrepareToReadKey
:
2981 ControlFlag
= CfReadKey
;
2982 ScreenOperation
= UiNoOperation
;
2986 ControlFlag
= CfScreenOperation
;
2989 // Wait for user's selection
2992 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2993 } while (Status
== EFI_TIMEOUT
);
2995 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2997 // IFR is updated in Callback of refresh opcode, re-parse it
2999 ControlFlag
= CfCheckSelection
;
3000 Selection
->Statement
= NULL
;
3004 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3006 // If we encounter error, continue to read another key in.
3008 if (EFI_ERROR (Status
)) {
3009 ControlFlag
= CfReadKey
;
3013 switch (Key
.UnicodeChar
) {
3014 case CHAR_CARRIAGE_RETURN
:
3015 if(MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3016 ControlFlag
= CfReadKey
;
3020 ScreenOperation
= UiSelect
;
3025 // We will push the adjustment of these numeric values directly to the input handler
3026 // NOTE: we won't handle manual input numeric
3031 // If the screen has no menu items, and the user didn't select UiReset
3032 // ignore the selection and go back to reading keys.
3034 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3035 ControlFlag
= CfReadKey
;
3039 ASSERT(MenuOption
!= NULL
);
3040 Statement
= MenuOption
->ThisTag
;
3041 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
3042 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
3043 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
3045 if (Key
.UnicodeChar
== '+') {
3046 gDirection
= SCAN_RIGHT
;
3048 gDirection
= SCAN_LEFT
;
3050 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
3051 if (EFI_ERROR (Status
)) {
3053 // Repaint to clear possible error prompt pop-up
3058 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3060 if (OptionString
!= NULL
) {
3061 FreePool (OptionString
);
3067 ScreenOperation
= UiUp
;
3072 ScreenOperation
= UiDown
;
3076 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
3078 // If the screen has no menu items, and the user didn't select UiReset
3079 // ignore the selection and go back to reading keys.
3081 if(IsListEmpty (&gMenuOption
)) {
3082 ControlFlag
= CfReadKey
;
3086 ASSERT(MenuOption
!= NULL
);
3087 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3088 ScreenOperation
= UiSelect
;
3095 if (!MultiHelpPage
) {
3096 ControlFlag
= CfReadKey
;
3099 ControlFlag
= CfUpdateHelpString
;
3100 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3105 if (!MultiHelpPage
) {
3106 ControlFlag
= CfReadKey
;
3109 ControlFlag
= CfUpdateHelpString
;
3110 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3114 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3115 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3116 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3121 if (Selection
->Form
->ModalForm
&& (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3123 // ModalForm has no ESC key and Hot Key.
3125 ControlFlag
= CfReadKey
;
3126 } else if (Index
== mScanCodeNumber
) {
3128 // Check whether Key matches the registered hot key.
3131 if ((gBrowserSettingScope
== SystemLevel
) || (gFunctionKeySetting
!= NONE_FUNCTION_KEY_SETTING
)) {
3132 HotKey
= GetHotKeyFromRegisterList (&Key
);
3134 if (HotKey
!= NULL
) {
3135 ScreenOperation
= UiHotKey
;
3142 case CfScreenOperation
:
3143 if (ScreenOperation
!= UiReset
) {
3145 // If the screen has no menu items, and the user didn't select UiReset
3146 // ignore the selection and go back to reading keys.
3148 if (IsListEmpty (&gMenuOption
)) {
3149 ControlFlag
= CfReadKey
;
3155 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
3158 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3159 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3166 ControlFlag
= CfCheckSelection
;
3168 ASSERT(MenuOption
!= NULL
);
3169 Statement
= MenuOption
->ThisTag
;
3170 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
3175 // Keep highlight on current MenuOption
3177 Selection
->QuestionId
= Statement
->QuestionId
;
3179 switch (Statement
->Operand
) {
3180 case EFI_IFR_REF_OP
:
3181 ProcessGotoOpCode(Statement
, Selection
, &Repaint
, &NewLine
);
3184 case EFI_IFR_ACTION_OP
:
3186 // Process the Config string <ConfigResp>
3188 Status
= ProcessQuestionConfig (Selection
, Statement
);
3190 if (EFI_ERROR (Status
)) {
3195 // The action button may change some Question value, so refresh the form
3197 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3200 case EFI_IFR_RESET_BUTTON_OP
:
3202 // Reset Question to default value specified by DefaultId
3204 ControlFlag
= CfUiDefault
;
3205 DefaultId
= Statement
->DefaultId
;
3210 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3212 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
3213 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
3215 if (EFI_ERROR (Status
)) {
3218 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
3220 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3223 if (OptionString
!= NULL
) {
3224 FreePool (OptionString
);
3232 // We come here when someone press ESC
3234 ControlFlag
= CfCheckSelection
;
3235 FindNextMenu (Selection
, &Repaint
, &NewLine
);
3239 ControlFlag
= CfCheckSelection
;
3240 ASSERT(MenuOption
!= NULL
);
3241 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3242 if (MenuOption
->Sequence
!= 0) {
3244 // In the middle or tail of the Date/Time op-code set, go left.
3246 ASSERT(NewPos
!= NULL
);
3247 NewPos
= NewPos
->BackLink
;
3253 ControlFlag
= CfCheckSelection
;
3254 ASSERT(MenuOption
!= NULL
);
3255 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
3256 if (MenuOption
->Sequence
!= 2) {
3258 // In the middle or tail of the Date/Time op-code set, go left.
3260 ASSERT(NewPos
!= NULL
);
3261 NewPos
= NewPos
->ForwardLink
;
3267 ControlFlag
= CfCheckSelection
;
3269 SavedListEntry
= NewPos
;
3271 ASSERT(NewPos
!= NULL
);
3273 // Adjust Date/Time position before we advance forward.
3275 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3276 if (NewPos
->BackLink
!= &gMenuOption
) {
3277 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3278 ASSERT (MenuOption
!= NULL
);
3280 NewPos
= NewPos
->BackLink
;
3282 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3283 if (PreviousMenuOption
->Row
== 0) {
3284 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3286 DistanceValue
= PreviousMenuOption
->Skip
;
3288 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
3289 Difference
= MoveToNextStatement (Selection
, TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
3291 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3293 if (Difference
< 0) {
3295 // We hit the begining MenuOption that can be focused
3296 // so we simply scroll to the top.
3298 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3299 TopOfScreen
= gMenuOption
.ForwardLink
;
3303 // Scroll up to the last page when we have arrived at top page.
3305 NewPos
= &gMenuOption
;
3306 TopOfScreen
= &gMenuOption
;
3307 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3308 ScreenOperation
= UiPageUp
;
3309 ControlFlag
= CfScreenOperation
;
3312 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
3314 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3316 TopOfScreen
= NewPos
;
3320 } else if (!IsSelectable (NextMenuOption
)) {
3322 // Continue to go up until scroll to next page or the selectable option is found.
3324 ScreenOperation
= UiUp
;
3325 ControlFlag
= CfScreenOperation
;
3329 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3331 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3332 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3333 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3334 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3337 // Scroll up to the last page.
3339 NewPos
= &gMenuOption
;
3340 TopOfScreen
= &gMenuOption
;
3341 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3342 ScreenOperation
= UiPageUp
;
3343 ControlFlag
= CfScreenOperation
;
3348 ControlFlag
= CfCheckSelection
;
3350 ASSERT(NewPos
!= NULL
);
3351 if (NewPos
->BackLink
== &gMenuOption
) {
3361 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
3362 Link
= Link
->BackLink
;
3363 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3364 if (PreviousMenuOption
->Row
== 0) {
3365 UpdateOptionSkipLines (Selection
, PreviousMenuOption
);
3367 if (Index
< PreviousMenuOption
->Skip
) {
3371 Index
= Index
- PreviousMenuOption
->Skip
;
3374 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
3375 if (TopOfScreen
== &gMenuOption
) {
3376 TopOfScreen
= gMenuOption
.ForwardLink
;
3377 NewPos
= gMenuOption
.BackLink
;
3378 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3380 } else if (TopOfScreen
!= Link
) {
3383 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3386 // Finally we know that NewPos is the last MenuOption can be focused.
3390 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3393 if (Index
+ 1 < TopRow
) {
3395 // Back up the previous option.
3397 Link
= Link
->ForwardLink
;
3401 // Move to the option in Next page.
3403 if (TopOfScreen
== &gMenuOption
) {
3404 NewPos
= gMenuOption
.BackLink
;
3405 MoveToNextStatement (Selection
, TRUE
, &NewPos
, BottomRow
- TopRow
);
3408 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3412 // There are more MenuOption needing scrolling up.
3419 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3420 // Don't do this when we are already in the first page.
3422 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3423 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3427 ControlFlag
= CfCheckSelection
;
3429 ASSERT (NewPos
!= NULL
);
3430 if (NewPos
->ForwardLink
== &gMenuOption
) {
3439 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3441 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
3442 Index
= Index
+ NextMenuOption
->Skip
;
3443 Link
= Link
->ForwardLink
;
3444 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3447 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
3449 // Finally we know that NewPos is the last MenuOption can be focused.
3452 MoveToNextStatement (Selection
, TRUE
, &Link
, Index
- TopRow
);
3454 if (Index
- 1 > BottomRow
) {
3456 // Back up the previous option.
3458 Link
= Link
->BackLink
;
3461 // There are more MenuOption needing scrolling down.
3466 // Move to the option in Next page.
3468 MoveToNextStatement (Selection
, FALSE
, &Link
, BottomRow
- TopRow
);
3472 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3473 // Don't do this when we are already in the last page.
3476 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3477 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3481 ControlFlag
= CfCheckSelection
;
3483 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3484 // to be one that progresses to the next set of op-codes, we need to advance to the last
3485 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3486 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3487 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3488 // the Date/Time op-code.
3490 SavedListEntry
= NewPos
;
3491 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3493 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3494 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3496 NewPos
= NewPos
->ForwardLink
;
3499 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3500 Difference
= MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3502 // We hit the end of MenuOption that can be focused
3503 // so we simply scroll to the first page.
3505 if (Difference
< 0) {
3507 // Scroll to the first page.
3509 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3510 TopOfScreen
= gMenuOption
.ForwardLink
;
3514 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3516 NewPos
= gMenuOption
.ForwardLink
;
3517 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3520 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3522 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3523 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3527 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3530 // An option might be multi-line, so we need to reflect that data in the overall skip value
3532 UpdateOptionSkipLines (Selection
, NextMenuOption
);
3533 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3535 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3536 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3537 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3538 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3544 // If we are going to scroll, update TopOfScreen
3546 if (Temp
> BottomRow
) {
3549 // Is the current top of screen a zero-advance op-code?
3550 // If so, keep moving forward till we hit a >0 advance op-code
3552 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3555 // If bottom op-code is more than one line or top op-code is more than one line
3557 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3559 // Is the bottom op-code greater than or equal in size to the top op-code?
3561 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3563 // Skip the top op-code
3565 TopOfScreen
= TopOfScreen
->ForwardLink
;
3566 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3568 OldSkipValue
= Difference
;
3570 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3573 // If we have a remainder, skip that many more op-codes until we drain the remainder
3575 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3577 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3579 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3580 TopOfScreen
= TopOfScreen
->ForwardLink
;
3581 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3584 // Since we will act on this op-code in the next routine, and increment the
3585 // SkipValue, set the skips to one less than what is required.
3587 SkipValue
= Difference
- 1;
3591 // Since we will act on this op-code in the next routine, and increment the
3592 // SkipValue, set the skips to one less than what is required.
3594 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3597 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3598 TopOfScreen
= TopOfScreen
->ForwardLink
;
3601 SkipValue
= OldSkipValue
;
3605 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3606 // Let's set a skip flag to smoothly scroll the top of the screen.
3608 if (SavedMenuOption
->Skip
> 1) {
3609 if (SavedMenuOption
== NextMenuOption
) {
3614 } else if (SavedMenuOption
->Skip
== 1) {
3618 TopOfScreen
= TopOfScreen
->ForwardLink
;
3620 } while (SavedMenuOption
->Skip
== 0);
3623 OldSkipValue
= SkipValue
;
3624 } else if (!IsSelectable (NextMenuOption
)) {
3626 // Continue to go down until scroll to next page or the selectable option is found.
3628 ScreenOperation
= UiDown
;
3629 ControlFlag
= CfScreenOperation
;
3632 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3634 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3638 // Scroll to the first page.
3640 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3641 TopOfScreen
= gMenuOption
.ForwardLink
;
3645 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3648 NewPos
= gMenuOption
.ForwardLink
;
3649 MoveToNextStatement (Selection
, FALSE
, &NewPos
, BottomRow
- TopRow
);
3653 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3655 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3656 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3660 ControlFlag
= CfCheckSelection
;
3662 Status
= EFI_SUCCESS
;
3664 // Discard changes. After it, no NV flag is showed.
3666 if ((HotKey
->Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
3667 Status
= DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3668 if (!EFI_ERROR (Status
)) {
3669 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3670 Selection
->Statement
= NULL
;
3671 gResetRequired
= FALSE
;
3674 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDiscardFailed
, gPressEnter
, gEmptyString
);
3675 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3677 // Still show current page.
3679 Selection
->Action
= UI_ACTION_NONE
;
3687 // Reterieve default setting. After it. NV flag will be showed.
3689 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3690 Status
= ExtractDefault (Selection
->FormSet
, Selection
->Form
, HotKey
->DefaultId
, gBrowserSettingScope
);
3691 if (!EFI_ERROR (Status
)) {
3692 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3693 Selection
->Statement
= NULL
;
3694 gResetRequired
= TRUE
;
3697 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gDefaultFailed
, gPressEnter
, gEmptyString
);
3698 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3700 // Still show current page.
3702 Selection
->Action
= UI_ACTION_NONE
;
3710 // Save changes. After it, no NV flag is showed.
3712 if ((HotKey
->Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
3713 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3714 if (!EFI_ERROR (Status
)) {
3715 ASSERT(MenuOption
!= NULL
);
3716 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3717 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3720 CreateDialog (4, TRUE
, 0, NULL
, &Key
, HotKey
->HelpString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3721 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3723 // Still show current page.
3725 Selection
->Action
= UI_ACTION_NONE
;
3733 // Set Reset required Flag
3735 if ((HotKey
->Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
3736 gResetRequired
= TRUE
;
3742 if ((HotKey
->Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
3744 // Form Exit without saving, Similar to ESC Key.
3745 // FormSet Exit without saving, Exit SendForm.
3746 // System Exit without saving, CallExitHandler and Exit SendForm.
3748 DiscardForm (Selection
->FormSet
, Selection
->Form
, gBrowserSettingScope
);
3749 if (gBrowserSettingScope
== FormLevel
) {
3750 ControlFlag
= CfUiReset
;
3751 } else if (gBrowserSettingScope
== FormSetLevel
) {
3752 Selection
->Action
= UI_ACTION_EXIT
;
3753 } else if (gBrowserSettingScope
== SystemLevel
) {
3754 if (ExitHandlerFunction
!= NULL
) {
3755 ExitHandlerFunction ();
3757 Selection
->Action
= UI_ACTION_EXIT
;
3759 Selection
->Statement
= NULL
;
3764 ControlFlag
= CfCheckSelection
;
3766 // Reset to default value for all forms in the whole system.
3768 Status
= ExtractDefault (Selection
->FormSet
, NULL
, DefaultId
, FormSetLevel
);
3770 if (!EFI_ERROR (Status
)) {
3771 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3772 Selection
->Statement
= NULL
;
3773 gResetRequired
= TRUE
;
3777 case CfUiNoOperation
:
3778 ControlFlag
= CfCheckSelection
;
3782 UiFreeRefreshList ();
3784 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3785 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3786 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3787 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");