2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 LIST_ENTRY gMenuOption
;
18 LIST_ENTRY gMenuList
= INITIALIZE_LIST_HEAD_VARIABLE (gMenuList
);
19 MENU_REFRESH_ENTRY
*gMenuRefreshHead
;
22 // Search table for UiDisplayMenu()
24 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
63 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
111 BOOLEAN GetLineByWidthFinished
= FALSE
;
115 Set Buffer to Value for Size bytes.
117 @param Buffer Memory to set.
118 @param Size Number of bytes to set
119 @param Value Value of the set operation.
132 while ((Size
--) != 0) {
139 Initialize Menu option list.
147 InitializeListHead (&gMenuOption
);
152 Free Menu option linked list.
160 UI_MENU_OPTION
*MenuOption
;
162 while (!IsListEmpty (&gMenuOption
)) {
163 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
164 RemoveEntryList (&MenuOption
->Link
);
167 // We allocated space for this description when we did a GetToken, free it here
169 if (MenuOption
->Skip
!= 0) {
171 // For date/time, MenuOption->Description is shared by three Menu Options
172 // Data format : [01/02/2004] [11:22:33]
173 // Line number : 0 0 1 0 0 1
175 FreePool (MenuOption
->Description
);
177 FreePool (MenuOption
);
183 Create a menu with specified formset GUID and form ID, and add it as a child
184 of the given parent menu.
186 @param Parent The parent of menu to be added.
187 @param FormSetGuid The Formset Guid of menu to be added.
188 @param FormId The Form ID of menu to be added.
190 @return A pointer to the newly added menu or NULL if memory is insufficient.
195 IN OUT UI_MENU_LIST
*Parent
,
196 IN EFI_GUID
*FormSetGuid
,
200 UI_MENU_LIST
*MenuList
;
202 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
203 if (MenuList
== NULL
) {
207 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
208 InitializeListHead (&MenuList
->ChildListHead
);
210 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
211 MenuList
->FormId
= FormId
;
212 MenuList
->Parent
= Parent
;
214 if (Parent
== NULL
) {
216 // If parent is not specified, it is the root Form of a Formset
218 InsertTailList (&gMenuList
, &MenuList
->Link
);
220 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
228 Search Menu with given FormId in the parent menu and all its child menus.
230 @param Parent The parent of menu to search.
231 @param FormId The Form ID of menu to search.
233 @return A pointer to menu found or NULL if not found.
237 UiFindChildMenuList (
238 IN UI_MENU_LIST
*Parent
,
244 UI_MENU_LIST
*MenuList
;
246 if (Parent
->FormId
== FormId
) {
250 Link
= GetFirstNode (&Parent
->ChildListHead
);
251 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
252 Child
= UI_MENU_LIST_FROM_LINK (Link
);
254 MenuList
= UiFindChildMenuList (Child
, FormId
);
255 if (MenuList
!= NULL
) {
259 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
267 Search Menu with given FormSetGuid and FormId in all cached menu list.
269 @param FormSetGuid The Formset GUID of the menu to search.
270 @param FormId The Form ID of menu to search.
272 @return A pointer to menu found or NULL if not found.
277 IN EFI_GUID
*FormSetGuid
,
282 UI_MENU_LIST
*MenuList
;
285 Link
= GetFirstNode (&gMenuList
);
286 while (!IsNull (&gMenuList
, Link
)) {
287 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
289 if (CompareGuid (FormSetGuid
, &MenuList
->FormSetGuid
)) {
291 // This is the formset we are looking for, find the form in this formset
293 Child
= UiFindChildMenuList (MenuList
, FormId
);
299 Link
= GetNextNode (&gMenuList
, Link
);
307 Free Menu option linked list.
315 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
317 while (gMenuRefreshHead
!= NULL
) {
318 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
319 FreePool (gMenuRefreshHead
);
320 gMenuRefreshHead
= OldMenuRefreshEntry
;
323 gMenuRefreshHead
= NULL
;
337 CHAR16
*OptionString
;
338 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
341 UI_MENU_SELECTION
*Selection
;
342 FORM_BROWSER_STATEMENT
*Question
;
344 if (gMenuRefreshHead
!= NULL
) {
346 MenuRefreshEntry
= gMenuRefreshHead
;
349 // Reset FormPackage update flag
351 mHiiPackageListUpdated
= FALSE
;
354 Selection
= MenuRefreshEntry
->Selection
;
355 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
357 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
358 if (EFI_ERROR (Status
)) {
363 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
365 if (OptionString
!= NULL
) {
367 // If leading spaces on OptionString - remove the spaces
369 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
373 // If old Text is longer than new string, need to clean the old string before paint the newer.
374 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
376 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
377 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
379 MenuRefreshEntry
->CurrentColumn
,
380 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
381 MenuRefreshEntry
->CurrentRow
,
382 MenuRefreshEntry
->CurrentRow
,
383 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
387 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
388 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
389 FreePool (OptionString
);
393 // Question value may be changed, need invoke its Callback()
395 Status
= ProcessCallBackFunction(Selection
, Question
, EFI_BROWSER_ACTION_CHANGING
, FALSE
);
396 if (EFI_ERROR (Status
)) {
400 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
402 } while (MenuRefreshEntry
!= NULL
);
404 if (mHiiPackageListUpdated
) {
406 // Package list is updated, force to reparse IFR binary of target Formset
408 mHiiPackageListUpdated
= FALSE
;
409 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
419 Wait for a given event to fire, or for an optional timeout to expire.
421 @param Event The event to wait for
422 @param Timeout An optional timeout value in 100 ns units.
423 @param RefreshInterval Menu refresh interval (in seconds).
425 @retval EFI_SUCCESS Event fired before Timeout expired.
426 @retval EFI_TIME_OUT Timout expired before Event fired.
430 UiWaitForSingleEvent (
432 IN UINT64 Timeout
, OPTIONAL
433 IN UINT8 RefreshInterval OPTIONAL
438 EFI_EVENT TimerEvent
;
439 EFI_EVENT WaitList
[2];
443 // Create a timer event
445 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
446 if (!EFI_ERROR (Status
)) {
448 // Set the timer event
457 // Wait for the original event or the timer
460 WaitList
[1] = TimerEvent
;
461 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
462 gBS
->CloseEvent (TimerEvent
);
465 // If the timer expired, change the return to timed out
467 if (!EFI_ERROR (Status
) && Index
== 1) {
468 Status
= EFI_TIMEOUT
;
473 // Update screen every second
475 if (RefreshInterval
== 0) {
476 Timeout
= ONE_SECOND
;
478 Timeout
= RefreshInterval
* ONE_SECOND
;
482 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
485 // Set the timer event
494 // Wait for the original event or the timer
497 WaitList
[1] = TimerEvent
;
498 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
501 // If the timer expired, update anything that needs a refresh and keep waiting
503 if (!EFI_ERROR (Status
) && Index
== 1) {
504 Status
= EFI_TIMEOUT
;
505 if (RefreshInterval
!= 0) {
506 Status
= RefreshForm ();
510 gBS
->CloseEvent (TimerEvent
);
511 } while (Status
== EFI_TIMEOUT
);
519 Add one menu option by specified description and context.
521 @param String String description for this option.
522 @param Handle Hii handle for the package list.
523 @param Statement Statement of this Menu Option.
524 @param NumberOfLines Display lines for this Menu Option.
525 @param MenuItemCount The index for this Option in the Menu.
527 @retval Pointer Pointer to the added Menu Option.
533 IN EFI_HII_HANDLE Handle
,
534 IN FORM_BROWSER_STATEMENT
*Statement
,
535 IN UINT16 NumberOfLines
,
536 IN UINT16 MenuItemCount
539 UI_MENU_OPTION
*MenuOption
;
546 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
548 // Add three MenuOptions for Date/Time
549 // Data format : [01/02/2004] [11:22:33]
550 // Line number : 0 0 1 0 0 1
555 if (Statement
->Storage
== NULL
) {
557 // For RTC type of date/time, set default refresh interval to be 1 second
559 if (Statement
->RefreshInterval
== 0) {
560 Statement
->RefreshInterval
= 1;
565 for (Index
= 0; Index
< Count
; Index
++) {
566 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
569 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
570 MenuOption
->Description
= String
;
571 MenuOption
->Handle
= Handle
;
572 MenuOption
->ThisTag
= Statement
;
573 MenuOption
->EntryNumber
= MenuItemCount
;
577 // Override LineNumber for the MenuOption in Date/Time sequence
579 MenuOption
->Skip
= 1;
581 MenuOption
->Skip
= NumberOfLines
;
583 MenuOption
->Sequence
= Index
;
585 if (Statement
->GrayOutExpression
!= NULL
) {
586 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
589 switch (Statement
->Operand
) {
590 case EFI_IFR_ORDERED_LIST_OP
:
591 case EFI_IFR_ONE_OF_OP
:
592 case EFI_IFR_NUMERIC_OP
:
593 case EFI_IFR_TIME_OP
:
594 case EFI_IFR_DATE_OP
:
595 case EFI_IFR_CHECKBOX_OP
:
596 case EFI_IFR_PASSWORD_OP
:
597 case EFI_IFR_STRING_OP
:
599 // User could change the value of these items
601 MenuOption
->IsQuestion
= TRUE
;
604 case EFI_IFR_TEXT_OP
:
605 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
607 // Initializing GrayOut option as TRUE for Text setup options
608 // so that those options will be Gray in colour and un selectable.
610 MenuOption
->GrayOut
= TRUE
;
614 MenuOption
->IsQuestion
= FALSE
;
618 if ((Statement
->ValueExpression
!= NULL
) ||
619 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
620 MenuOption
->ReadOnly
= TRUE
;
623 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
631 Routine used to abstract a generic dialog interface and return the selected key or string
633 @param NumberOfLines The number of lines for the dialog box
634 @param HotKey Defines whether a single character is parsed
635 (TRUE) and returned in KeyValue or a string is
636 returned in StringBuffer. Two special characters
637 are considered when entering a string, a SCAN_ESC
638 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
639 string input and returns
640 @param MaximumStringSize The maximum size in bytes of a typed in string
641 (each character is a CHAR16) and the minimum
642 string returned is two bytes
643 @param StringBuffer The passed in pointer to the buffer which will
644 hold the typed in string if HotKey is FALSE
645 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
646 @param ... A series of (quantity == NumberOfLines) text
647 strings which will be used to construct the dialog
650 @retval EFI_SUCCESS Displayed dialog and received user interaction
651 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
652 (StringBuffer == NULL) && (HotKey == FALSE))
653 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
659 IN UINTN NumberOfLines
,
661 IN UINTN MaximumStringSize
,
662 OUT CHAR16
*StringBuffer
,
663 OUT EFI_INPUT_KEY
*KeyValue
,
672 CHAR16
*BufferedString
;
679 BOOLEAN SelectionComplete
;
681 UINTN CurrentAttribute
;
682 UINTN DimensionsWidth
;
683 UINTN DimensionsHeight
;
685 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
686 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
688 SelectionComplete
= FALSE
;
690 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
691 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
692 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
695 ASSERT (BufferedString
);
697 VA_START (Marker
, KeyValue
);
700 // Zero the outgoing buffer
702 ZeroMem (StringBuffer
, MaximumStringSize
);
705 if (KeyValue
== NULL
) {
706 return EFI_INVALID_PARAMETER
;
709 if (StringBuffer
== NULL
) {
710 return EFI_INVALID_PARAMETER
;
716 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
721 // Determine the largest string in the dialog box
722 // Notice we are starting with 1 since String is the first string
724 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
725 StackString
= VA_ARG (Marker
, CHAR16
*);
727 if (StackString
[0] == L
' ') {
728 InputOffset
= Count
+ 1;
731 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
733 // Size of the string visually and subtract the width by one for the null-terminator
735 LargestString
= (GetStringWidth (StackString
) / 2);
740 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
741 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
748 VA_START (Marker
, KeyValue
);
749 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
753 // Take the first key typed and report it back?
756 Status
= WaitForKeyStroke (&Key
);
757 ASSERT_EFI_ERROR (Status
);
758 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
762 Status
= WaitForKeyStroke (&Key
);
764 switch (Key
.UnicodeChar
) {
766 switch (Key
.ScanCode
) {
768 FreePool (TempString
);
769 FreePool (BufferedString
);
770 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
771 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
772 return EFI_DEVICE_ERROR
;
780 case CHAR_CARRIAGE_RETURN
:
781 SelectionComplete
= TRUE
;
782 FreePool (TempString
);
783 FreePool (BufferedString
);
784 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
785 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
790 if (StringBuffer
[0] != CHAR_NULL
) {
791 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
792 TempString
[Index
] = StringBuffer
[Index
];
795 // Effectively truncate string by 1 character
797 TempString
[Index
- 1] = CHAR_NULL
;
798 StrCpy (StringBuffer
, TempString
);
803 // If it is the beginning of the string, don't worry about checking maximum limits
805 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
806 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
807 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
808 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
809 KeyPad
[0] = Key
.UnicodeChar
;
810 KeyPad
[1] = CHAR_NULL
;
811 StrCat (StringBuffer
, KeyPad
);
812 StrCat (TempString
, KeyPad
);
815 // If the width of the input string is now larger than the screen, we nee to
816 // adjust the index to start printing portions of the string
818 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
820 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
822 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
823 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
828 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
829 BufferedString
[Count
] = StringBuffer
[Index
];
832 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
835 } while (!SelectionComplete
);
838 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
839 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
844 Draw a pop up windows based on the dimension, number of lines and
847 @param RequestedWidth The width of the pop-up.
848 @param NumberOfLines The number of lines.
849 @param Marker The variable argument list for the list of string to be printed.
854 IN UINTN RequestedWidth
,
855 IN UINTN NumberOfLines
,
867 UINTN DimensionsWidth
;
868 UINTN DimensionsHeight
;
870 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
871 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
873 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
875 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
876 RequestedWidth
= DimensionsWidth
- 2;
880 // Subtract the PopUp width from total Columns, allow for one space extra on
881 // each end plus a border.
883 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
884 End
= Start
+ RequestedWidth
+ 1;
886 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
887 Bottom
= Top
+ NumberOfLines
+ 2;
889 Character
= BOXDRAW_DOWN_RIGHT
;
890 PrintCharAt (Start
, Top
, Character
);
891 Character
= BOXDRAW_HORIZONTAL
;
892 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
893 PrintChar (Character
);
896 Character
= BOXDRAW_DOWN_LEFT
;
897 PrintChar (Character
);
898 Character
= BOXDRAW_VERTICAL
;
901 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
902 String
= VA_ARG (Marker
, CHAR16
*);
905 // This will clear the background of the line - we never know who might have been
906 // here before us. This differs from the next clear in that it used the non-reverse
907 // video for normal printing.
909 if (GetStringWidth (String
) / 2 > 1) {
910 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
914 // Passing in a space results in the assumption that this is where typing will occur
916 if (String
[0] == L
' ') {
917 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
921 // Passing in a NULL results in a blank space
923 if (String
[0] == CHAR_NULL
) {
924 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
928 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
932 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
933 PrintCharAt (Start
, Index
+ 1, Character
);
934 PrintCharAt (End
- 1, Index
+ 1, Character
);
937 Character
= BOXDRAW_UP_RIGHT
;
938 PrintCharAt (Start
, Bottom
- 1, Character
);
939 Character
= BOXDRAW_HORIZONTAL
;
940 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
941 PrintChar (Character
);
944 Character
= BOXDRAW_UP_LEFT
;
945 PrintChar (Character
);
949 Draw a pop up windows based on the dimension, number of lines and
952 @param RequestedWidth The width of the pop-up.
953 @param NumberOfLines The number of lines.
954 @param ... A series of text strings that displayed in the pop-up.
959 CreateMultiStringPopUp (
960 IN UINTN RequestedWidth
,
961 IN UINTN NumberOfLines
,
967 VA_START (Marker
, NumberOfLines
);
969 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
976 Update status bar on the bottom of menu.
978 @param Selection Current Selction info.
979 @param MessageType The type of message to be shown.
980 @param Flags The flags in Question header.
981 @param State Set or clear.
986 IN UI_MENU_SELECTION
*Selection
,
987 IN UINTN MessageType
,
993 CHAR16
*NvUpdateMessage
;
994 CHAR16
*InputErrorMessage
;
996 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
997 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
999 switch (MessageType
) {
1002 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1004 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1005 gScreenDimensions
.BottomRow
- 1,
1010 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1011 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1012 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1015 mInputError
= FALSE
;
1019 case NV_UPDATE_REQUIRED
:
1020 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
1022 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1024 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1025 gScreenDimensions
.BottomRow
- 1,
1028 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1030 if (Selection
!= NULL
) {
1031 Selection
->Form
->NvUpdateRequired
= TRUE
;
1034 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1035 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1037 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1038 gScreenDimensions
.BottomRow
- 1,
1043 if (Selection
!= NULL
) {
1044 Selection
->Form
->NvUpdateRequired
= FALSE
;
1050 case REFRESH_STATUS_BAR
:
1052 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1055 if (IsNvUpdateRequired(Selection
->FormSet
)) {
1056 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1064 FreePool (InputErrorMessage
);
1065 FreePool (NvUpdateMessage
);
1071 Get the supported width for a particular op-code
1073 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1074 @param Handle The handle in the HII database being used
1076 @return Returns the number of CHAR16 characters that is support.
1081 IN FORM_BROWSER_STATEMENT
*Statement
,
1082 IN EFI_HII_HANDLE Handle
1092 // See if the second text parameter is really NULL
1094 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1095 String
= GetToken (Statement
->TextTwo
, Handle
);
1096 Size
= StrLen (String
);
1100 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1101 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1102 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1103 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1104 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1106 // Allow a wide display if text op-code and no secondary text op-code
1108 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1110 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1112 Width
= (UINT16
) gPromptBlockWidth
;
1115 if (Statement
->InSubtitle
) {
1116 Width
-= SUBTITLE_INDENT
;
1119 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1123 Will copy LineWidth amount of a string in the OutputString buffer and return the
1124 number of CHAR16 characters that were copied into the OutputString buffer.
1126 @param InputString String description for this option.
1127 @param LineWidth Width of the desired string to extract in CHAR16
1129 @param Index Where in InputString to start the copy process
1130 @param OutputString Buffer to copy the string into
1132 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1137 IN CHAR16
*InputString
,
1138 IN UINT16 LineWidth
,
1139 IN OUT UINTN
*Index
,
1140 OUT CHAR16
**OutputString
1146 if (GetLineByWidthFinished
) {
1147 GetLineByWidthFinished
= FALSE
;
1154 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1157 // Ensure we have got a valid buffer
1159 if (*OutputString
!= NULL
) {
1162 //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.
1163 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1165 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1166 *Index
= *Index
+ 2;
1170 // Fast-forward the string and see if there is a carriage-return in the string
1172 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1176 // Copy the desired LineWidth of data to the output buffer.
1177 // Also make sure that we don't copy more than the string.
1178 // Also make sure that if there are linefeeds, we account for them.
1180 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1181 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1184 // Convert to CHAR16 value and show that we are done with this operation
1186 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1187 if (LineWidth
!= 0) {
1188 GetLineByWidthFinished
= TRUE
;
1191 if (Count2
== LineWidth
) {
1193 // Rewind the string from the maximum size until we see a space to break the line
1195 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1197 if (LineWidth
== 0) {
1205 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1208 // If currently pointing to a space, increment the index to the first non-space character
1211 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1215 *Index
= (UINT16
) (*Index
+ LineWidth
);
1224 Update display lines for a Menu Option.
1226 @param Selection The user's selection.
1227 @param MenuOption The MenuOption to be checked.
1228 @param OptionalString The option string.
1229 @param SkipValue The number of lins to skip.
1233 UpdateOptionSkipLines (
1234 IN UI_MENU_SELECTION
*Selection
,
1235 IN UI_MENU_OPTION
*MenuOption
,
1236 OUT CHAR16
**OptionalString
,
1244 CHAR16
*OutputString
;
1245 CHAR16
*OptionString
;
1248 OptionString
= *OptionalString
;
1249 OutputString
= NULL
;
1251 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1253 if (OptionString
!= NULL
) {
1254 Width
= (UINT16
) gOptionBlockWidth
;
1258 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1260 // If there is more string to process print on the next row and increment the Skip value
1262 if (StrLen (&OptionString
[Index
]) != 0) {
1263 if (SkipValue
== 0) {
1266 // Since the Number of lines for this menu entry may or may not be reflected accurately
1267 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1268 // some testing to ensure we are keeping this in-sync.
1270 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1272 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1278 FreePool (OutputString
);
1279 if (SkipValue
!= 0) {
1287 *OptionalString
= OptionString
;
1292 Check whether this Menu Option could be highlighted.
1294 This is an internal function.
1296 @param MenuOption The MenuOption to be checked.
1298 @retval TRUE This Menu Option is selectable.
1299 @retval FALSE This Menu Option could not be selected.
1304 UI_MENU_OPTION
*MenuOption
1307 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1308 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1317 Determine if the menu is the last menu that can be selected.
1319 This is an internal function.
1321 @param Direction The scroll direction. False is down. True is up.
1322 @param CurrentPos The current focus.
1324 @return FALSE -- the menu isn't the last menu that can be selected.
1325 @return TRUE -- the menu is the last menu that can be selected.
1330 IN BOOLEAN Direction
,
1331 IN LIST_ENTRY
*CurrentPos
1336 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1338 if (Temp
== &gMenuOption
) {
1347 Move to next selectable statement.
1349 This is an internal function.
1351 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1352 @param CurrentPosition Current position.
1353 @param GapToTop Gap position to top or bottom.
1355 @return The row distance from current MenuOption to next selectable MenuOption.
1359 MoveToNextStatement (
1361 IN OUT LIST_ENTRY
**CurrentPosition
,
1367 UI_MENU_OPTION
*NextMenuOption
;
1368 UI_MENU_OPTION
*PreMenuOption
;
1371 Pos
= *CurrentPosition
;
1372 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1375 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1376 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1378 // Current Position doesn't need to be caculated when go up.
1379 // Caculate distanct at first when go up
1381 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1382 NextMenuOption
= PreMenuOption
;
1385 Distance
+= NextMenuOption
->Skip
;
1387 if (IsSelectable (NextMenuOption
)) {
1390 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1399 // Caculate distanct at later when go down
1401 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1402 NextMenuOption
= PreMenuOption
;
1405 Distance
+= NextMenuOption
->Skip
;
1407 PreMenuOption
= NextMenuOption
;
1408 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1411 *CurrentPosition
= &NextMenuOption
->Link
;
1417 Adjust Data and Time position accordingly.
1418 Data format : [01/02/2004] [11:22:33]
1419 Line number : 0 0 1 0 0 1
1421 This is an internal function.
1423 @param DirectionUp the up or down direction. False is down. True is
1425 @param CurrentPosition Current position. On return: Point to the last
1426 Option (Year or Second) if up; Point to the first
1427 Option (Month or Hour) if down.
1429 @return Return line number to pad. It is possible that we stand on a zero-advance
1430 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1434 AdjustDateAndTimePosition (
1435 IN BOOLEAN DirectionUp
,
1436 IN OUT LIST_ENTRY
**CurrentPosition
1440 LIST_ENTRY
*NewPosition
;
1441 UI_MENU_OPTION
*MenuOption
;
1442 UINTN PadLineNumber
;
1445 NewPosition
= *CurrentPosition
;
1446 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1448 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1449 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1451 // Calculate the distance from current position to the last Date/Time MenuOption
1454 while (MenuOption
->Skip
== 0) {
1456 NewPosition
= NewPosition
->ForwardLink
;
1457 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1461 NewPosition
= *CurrentPosition
;
1464 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1465 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1466 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1467 // checking can be done.
1469 while (Count
++ < 2) {
1470 NewPosition
= NewPosition
->BackLink
;
1474 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1475 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1476 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1477 // checking can be done.
1479 while (Count
-- > 0) {
1480 NewPosition
= NewPosition
->ForwardLink
;
1484 *CurrentPosition
= NewPosition
;
1487 return PadLineNumber
;
1491 Find HII Handle in the HII database associated with given Device Path.
1493 If DevicePath is NULL, then ASSERT.
1495 @param DevicePath Device Path associated with the HII package list
1498 @retval Handle HII package list Handle associated with the Device
1500 @retval NULL Hii Package list handle is not found.
1505 DevicePathToHiiHandle (
1506 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1510 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1515 EFI_HANDLE DriverHandle
;
1516 EFI_HII_HANDLE
*HiiHandles
;
1517 EFI_HII_HANDLE HiiHandle
;
1519 ASSERT (DevicePath
!= NULL
);
1521 TmpDevicePath
= DevicePath
;
1523 // Locate Device Path Protocol handle buffer
1525 Status
= gBS
->LocateDevicePath (
1526 &gEfiDevicePathProtocolGuid
,
1530 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1535 // Retrieve all HII Handles from HII database
1537 BufferSize
= 0x1000;
1538 HiiHandles
= AllocatePool (BufferSize
);
1539 ASSERT (HiiHandles
!= NULL
);
1540 Status
= mHiiDatabase
->ListPackageLists (
1542 EFI_HII_PACKAGE_TYPE_ALL
,
1547 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1548 FreePool (HiiHandles
);
1549 HiiHandles
= AllocatePool (BufferSize
);
1550 ASSERT (HiiHandles
!= NULL
);
1552 Status
= mHiiDatabase
->ListPackageLists (
1554 EFI_HII_PACKAGE_TYPE_ALL
,
1561 if (EFI_ERROR (Status
)) {
1562 FreePool (HiiHandles
);
1567 // Search Hii Handle by Driver Handle
1570 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1571 for (Index
= 0; Index
< HandleCount
; Index
++) {
1572 Status
= mHiiDatabase
->GetPackageListHandle (
1577 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1578 HiiHandle
= HiiHandles
[Index
];
1583 FreePool (HiiHandles
);
1588 Display menu and wait for user to select one menu option, then return it.
1589 If AutoBoot is enabled, then if user doesn't select any option,
1590 after period of time, it will automatically return the first menu option.
1592 @param Selection Menu selection.
1594 @retval EFI_SUCESSS This function always return successfully for now.
1599 IN OUT UI_MENU_SELECTION
*Selection
1605 UINTN DistanceValue
;
1617 CHAR16
*OptionString
;
1618 CHAR16
*OutputString
;
1619 CHAR16
*FormattedString
;
1625 BOOLEAN InitializedFlag
;
1630 LIST_ENTRY
*TopOfScreen
;
1631 LIST_ENTRY
*SavedListEntry
;
1632 UI_MENU_OPTION
*MenuOption
;
1633 UI_MENU_OPTION
*NextMenuOption
;
1634 UI_MENU_OPTION
*SavedMenuOption
;
1635 UI_MENU_OPTION
*PreviousMenuOption
;
1636 UI_CONTROL_FLAG ControlFlag
;
1637 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1638 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1639 UI_SCREEN_OPERATION ScreenOperation
;
1640 UINT8 MinRefreshInterval
;
1643 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1644 FORM_BROWSER_STATEMENT
*Statement
;
1646 UINT8
*DevicePathBuffer
;
1648 UI_MENU_LIST
*CurrentMenu
;
1649 UI_MENU_LIST
*MenuList
;
1650 FORM_BROWSER_FORM
*RefForm
;
1652 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1654 Status
= EFI_SUCCESS
;
1655 FormattedString
= NULL
;
1656 OptionString
= NULL
;
1657 ScreenOperation
= UiNoOperation
;
1659 MinRefreshInterval
= 0;
1662 OutputString
= NULL
;
1667 MenuRefreshEntry
= gMenuRefreshHead
;
1669 NextMenuOption
= NULL
;
1670 PreviousMenuOption
= NULL
;
1671 SavedMenuOption
= NULL
;
1674 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1676 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1677 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1678 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1680 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1681 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1684 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1685 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1687 Selection
->TopRow
= TopRow
;
1688 Selection
->BottomRow
= BottomRow
;
1689 Selection
->PromptCol
= Col
;
1690 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1691 Selection
->Statement
= NULL
;
1693 TopOfScreen
= gMenuOption
.ForwardLink
;
1698 // Find current Menu
1700 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1701 if (CurrentMenu
== NULL
) {
1703 // Current menu not found, add it to the menu tree
1705 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1707 ASSERT (CurrentMenu
!= NULL
);
1708 Selection
->CurrentMenu
= CurrentMenu
;
1710 if (Selection
->QuestionId
== 0) {
1712 // Highlight not specified, fetch it from cached menu
1714 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1718 // Init option as the current user's selection
1720 InitializedFlag
= TRUE
;
1721 NewPos
= gMenuOption
.ForwardLink
;
1723 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1724 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1726 ControlFlag
= CfInitialization
;
1727 Selection
->Action
= UI_ACTION_NONE
;
1729 switch (ControlFlag
) {
1730 case CfInitialization
:
1731 if (IsListEmpty (&gMenuOption
)) {
1732 ControlFlag
= CfReadKey
;
1734 ControlFlag
= CfCheckSelection
;
1738 case CfCheckSelection
:
1739 if (Selection
->Action
!= UI_ACTION_NONE
) {
1740 ControlFlag
= CfExit
;
1742 ControlFlag
= CfRepaint
;
1747 ControlFlag
= CfRefreshHighLight
;
1757 Temp
= (UINTN
) SkipValue
;
1758 Temp2
= (UINTN
) SkipValue
;
1761 LocalScreen
.LeftColumn
,
1762 LocalScreen
.RightColumn
,
1763 TopRow
- SCROLL_ARROW_HEIGHT
,
1764 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1765 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1768 UiFreeRefreshList ();
1769 MinRefreshInterval
= 0;
1771 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1772 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1773 MenuOption
->Row
= Row
;
1774 MenuOption
->Col
= Col
;
1775 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1777 Statement
= MenuOption
->ThisTag
;
1778 if (Statement
->InSubtitle
) {
1779 MenuOption
->Col
+= SUBTITLE_INDENT
;
1782 if (MenuOption
->GrayOut
) {
1783 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1785 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1786 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
1790 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1793 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1795 // Print Arrow for Goto button.
1798 MenuOption
->Col
- 2,
1801 GEOMETRICSHAPE_RIGHT_TRIANGLE
1805 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1806 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1807 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1810 // If there is more string to process print on the next row and increment the Skip value
1812 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1818 FreePool (OutputString
);
1827 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1828 if (EFI_ERROR (Status
)) {
1830 // Repaint to clear possible error prompt pop-up
1834 ControlFlag
= CfRepaint
;
1838 if (OptionString
!= NULL
) {
1839 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1841 // If leading spaces on OptionString - remove the spaces
1843 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1844 MenuOption
->OptCol
++;
1847 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1848 OptionString
[Count
] = OptionString
[Index
];
1852 OptionString
[Count
] = CHAR_NULL
;
1856 // If Question request refresh, register the op-code
1858 if (Statement
->RefreshInterval
!= 0) {
1860 // Menu will be refreshed at minimal interval of all Questions
1861 // which have refresh request
1863 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1864 MinRefreshInterval
= Statement
->RefreshInterval
;
1867 if (gMenuRefreshHead
== NULL
) {
1868 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1869 ASSERT (MenuRefreshEntry
!= NULL
);
1870 MenuRefreshEntry
->MenuOption
= MenuOption
;
1871 MenuRefreshEntry
->Selection
= Selection
;
1872 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1873 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1874 if (MenuOption
->GrayOut
) {
1875 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1877 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1879 gMenuRefreshHead
= MenuRefreshEntry
;
1882 // Advance to the last entry
1884 for (MenuRefreshEntry
= gMenuRefreshHead
;
1885 MenuRefreshEntry
->Next
!= NULL
;
1886 MenuRefreshEntry
= MenuRefreshEntry
->Next
1889 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1890 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1891 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1892 MenuRefreshEntry
->MenuOption
= MenuOption
;
1893 MenuRefreshEntry
->Selection
= Selection
;
1894 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1895 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1896 if (MenuOption
->GrayOut
) {
1897 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1899 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1904 Width
= (UINT16
) gOptionBlockWidth
;
1907 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1908 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1909 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1912 // If there is more string to process print on the next row and increment the Skip value
1914 if (StrLen (&OptionString
[Index
]) != 0) {
1918 // Since the Number of lines for this menu entry may or may not be reflected accurately
1919 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1920 // some testing to ensure we are keeping this in-sync.
1922 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1924 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1930 FreePool (OutputString
);
1939 FreePool (OptionString
);
1942 // If this is a text op with secondary text information
1944 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1945 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
1947 Width
= (UINT16
) gOptionBlockWidth
;
1950 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1951 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1952 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1955 // If there is more string to process print on the next row and increment the Skip value
1957 if (StrLen (&StringPtr
[Index
]) != 0) {
1961 // Since the Number of lines for this menu entry may or may not be reflected accurately
1962 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1963 // some testing to ensure we are keeping this in-sync.
1965 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1967 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1973 FreePool (OutputString
);
1980 FreePool (StringPtr
);
1982 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
1985 // Need to handle the bottom of the display
1987 if (MenuOption
->Skip
> 1) {
1988 Row
+= MenuOption
->Skip
- SkipValue
;
1991 Row
+= MenuOption
->Skip
;
1994 if (Row
> BottomRow
) {
1995 if (!ValueIsScroll (FALSE
, Link
)) {
1999 Row
= BottomRow
+ 1;
2004 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2009 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2011 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2012 TopRow
- SCROLL_ARROW_HEIGHT
,
2016 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2020 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2022 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2023 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2027 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2034 case CfRefreshHighLight
:
2036 // MenuOption: Last menu option that need to remove hilight
2037 // MenuOption is set to NULL in Repaint
2038 // NewPos: Current menu option that need to hilight
2040 ControlFlag
= CfUpdateHelpString
;
2041 if (InitializedFlag
) {
2042 InitializedFlag
= FALSE
;
2043 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2047 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2048 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2050 SavedValue
= Repaint
;
2053 if (Selection
->QuestionId
!= 0) {
2054 NewPos
= gMenuOption
.ForwardLink
;
2055 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2057 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &gMenuOption
) {
2058 NewPos
= NewPos
->ForwardLink
;
2059 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2061 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2063 // Target Question found, find its MenuOption
2067 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2068 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2069 Index
+= SavedMenuOption
->Skip
;
2070 Link
= Link
->ForwardLink
;
2073 if (Link
!= NewPos
|| Index
> BottomRow
) {
2075 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2078 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2079 Link
= Link
->BackLink
;
2080 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2081 Index
+= SavedMenuOption
->Skip
;
2083 TopOfScreen
= Link
->ForwardLink
;
2087 ControlFlag
= CfRepaint
;
2092 // Target Question not found, highlight the default menu option
2094 NewPos
= TopOfScreen
;
2097 Selection
->QuestionId
= 0;
2100 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2101 if (MenuOption
!= NULL
) {
2103 // Remove highlight on last Menu Option
2105 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2106 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2107 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2108 if (OptionString
!= NULL
) {
2109 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2110 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2113 // If leading spaces on OptionString - remove the spaces
2115 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2118 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2119 OptionString
[Count
] = OptionString
[Index
];
2123 OptionString
[Count
] = CHAR_NULL
;
2126 Width
= (UINT16
) gOptionBlockWidth
;
2127 OriginalRow
= MenuOption
->Row
;
2129 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2130 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2131 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2134 // If there is more string to process print on the next row and increment the Skip value
2136 if (StrLen (&OptionString
[Index
]) != 0) {
2140 FreePool (OutputString
);
2143 MenuOption
->Row
= OriginalRow
;
2145 FreePool (OptionString
);
2148 if (MenuOption
->GrayOut
) {
2149 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2150 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2151 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2154 OriginalRow
= MenuOption
->Row
;
2155 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2157 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2158 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2159 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2162 // If there is more string to process print on the next row and increment the Skip value
2164 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2168 FreePool (OutputString
);
2171 MenuOption
->Row
= OriginalRow
;
2172 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2178 // This is the current selected statement
2180 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2181 Statement
= MenuOption
->ThisTag
;
2182 Selection
->Statement
= Statement
;
2183 if (!IsSelectable (MenuOption
)) {
2184 Repaint
= SavedValue
;
2185 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2190 // Record highlight for current menu
2192 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2195 // Set reverse attribute
2197 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2198 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2201 // Assuming that we have a refresh linked-list created, lets annotate the
2202 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2203 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2205 if (gMenuRefreshHead
!= NULL
) {
2206 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2207 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2208 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2210 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2212 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2213 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2218 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2219 if (OptionString
!= NULL
) {
2220 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2222 // If leading spaces on OptionString - remove the spaces
2224 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2227 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2228 OptionString
[Count
] = OptionString
[Index
];
2232 OptionString
[Count
] = CHAR_NULL
;
2234 Width
= (UINT16
) gOptionBlockWidth
;
2236 OriginalRow
= MenuOption
->Row
;
2238 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2239 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2240 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2243 // If there is more string to process print on the next row and increment the Skip value
2245 if (StrLen (&OptionString
[Index
]) != 0) {
2249 FreePool (OutputString
);
2252 MenuOption
->Row
= OriginalRow
;
2254 FreePool (OptionString
);
2257 OriginalRow
= MenuOption
->Row
;
2259 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2261 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2262 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2263 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2266 // If there is more string to process print on the next row and increment the Skip value
2268 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2272 FreePool (OutputString
);
2275 MenuOption
->Row
= OriginalRow
;
2280 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2283 // Clear reverse attribute
2285 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2288 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2289 // if we didn't break halfway when process CfRefreshHighLight.
2291 Repaint
= SavedValue
;
2294 case CfUpdateHelpString
:
2295 ControlFlag
= CfPrepareToReadKey
;
2297 if (Repaint
|| NewLine
) {
2299 // Don't print anything if it is a NULL help token
2301 ASSERT(MenuOption
!= NULL
);
2302 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2305 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2308 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2310 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2312 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2314 // Pad String with spaces to simulate a clearing of the previous line
2316 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2317 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2321 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2323 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2328 // Reset this flag every time we finish using it.
2334 case CfPrepareToReadKey
:
2335 ControlFlag
= CfReadKey
;
2336 ScreenOperation
= UiNoOperation
;
2340 ControlFlag
= CfScreenOperation
;
2343 // Wait for user's selection
2346 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2347 } while (Status
== EFI_TIMEOUT
);
2349 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2351 // IFR is updated in Callback of refresh opcode, re-parse it
2353 Selection
->Statement
= NULL
;
2357 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2359 // If we encounter error, continue to read another key in.
2361 if (EFI_ERROR (Status
)) {
2362 ControlFlag
= CfReadKey
;
2366 switch (Key
.UnicodeChar
) {
2367 case CHAR_CARRIAGE_RETURN
:
2368 ScreenOperation
= UiSelect
;
2373 // We will push the adjustment of these numeric values directly to the input handler
2374 // NOTE: we won't handle manual input numeric
2379 // If the screen has no menu items, and the user didn't select UiReset
2380 // ignore the selection and go back to reading keys.
2382 if(IsListEmpty (&gMenuOption
)) {
2383 ControlFlag
= CfReadKey
;
2387 ASSERT(MenuOption
!= NULL
);
2388 Statement
= MenuOption
->ThisTag
;
2389 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2390 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2391 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2393 if (Key
.UnicodeChar
== '+') {
2394 gDirection
= SCAN_RIGHT
;
2396 gDirection
= SCAN_LEFT
;
2398 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2399 if (EFI_ERROR (Status
)) {
2401 // Repaint to clear possible error prompt pop-up
2406 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2408 if (OptionString
!= NULL
) {
2409 FreePool (OptionString
);
2415 ScreenOperation
= UiUp
;
2420 ScreenOperation
= UiDown
;
2424 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2426 // If the screen has no menu items, and the user didn't select UiReset
2427 // ignore the selection and go back to reading keys.
2429 if(IsListEmpty (&gMenuOption
)) {
2430 ControlFlag
= CfReadKey
;
2434 ASSERT(MenuOption
!= NULL
);
2435 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2436 ScreenOperation
= UiSelect
;
2442 if (((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2443 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2446 // If the function key has been disabled, just ignore the key.
2449 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2450 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2451 if (Key
.ScanCode
== SCAN_F9
) {
2453 // Reset to standard default
2455 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2457 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2466 case CfScreenOperation
:
2467 if (ScreenOperation
!= UiReset
) {
2469 // If the screen has no menu items, and the user didn't select UiReset
2470 // ignore the selection and go back to reading keys.
2472 if (IsListEmpty (&gMenuOption
)) {
2473 ControlFlag
= CfReadKey
;
2479 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2482 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2483 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2490 ControlFlag
= CfCheckSelection
;
2492 ASSERT(MenuOption
!= NULL
);
2493 Statement
= MenuOption
->ThisTag
;
2494 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2499 // Keep highlight on current MenuOption
2501 Selection
->QuestionId
= Statement
->QuestionId
;
2503 switch (Statement
->Operand
) {
2504 case EFI_IFR_REF_OP
:
2505 if (Statement
->RefDevicePath
!= 0) {
2507 // Goto another Hii Package list
2509 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2511 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2512 if (StringPtr
== NULL
) {
2514 // No device path string not found, exit
2516 Selection
->Action
= UI_ACTION_EXIT
;
2517 Selection
->Statement
= NULL
;
2520 BufferSize
= StrLen (StringPtr
) / 2;
2521 DevicePath
= AllocatePool (BufferSize
);
2522 ASSERT (DevicePath
!= NULL
);
2525 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2527 DevicePathBuffer
= (UINT8
*) DevicePath
;
2528 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2529 TemStr
[0] = StringPtr
[Index
];
2530 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2531 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2533 // Invalid Hex Char as the tail.
2537 if ((Index
& 1) == 0) {
2538 DevicePathBuffer
[Index
/2] = DigitUint8
;
2540 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2544 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2545 if (Selection
->Handle
== NULL
) {
2547 // If target Hii Handle not found, exit
2549 Selection
->Action
= UI_ACTION_EXIT
;
2550 Selection
->Statement
= NULL
;
2554 FreePool (StringPtr
);
2555 FreePool (DevicePath
);
2557 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2558 Selection
->FormId
= Statement
->RefFormId
;
2559 Selection
->QuestionId
= Statement
->RefQuestionId
;
2560 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2562 // Goto another Formset, check for uncommitted data
2564 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2566 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2567 Selection
->FormId
= Statement
->RefFormId
;
2568 Selection
->QuestionId
= Statement
->RefQuestionId
;
2569 } else if (Statement
->RefFormId
!= 0) {
2571 // Check whether target From is suppressed.
2573 RefForm
= IdToForm (Selection
->FormSet
, Statement
->RefFormId
);
2575 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2576 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
2577 if (EFI_ERROR (Status
)) {
2581 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
2583 // Form is suppressed.
2586 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2587 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2595 // Goto another form inside this formset,
2597 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2600 // Link current form so that we can always go back when someone hits the ESC
2602 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->RefFormId
);
2603 if (MenuList
== NULL
) {
2604 MenuList
= UiAddMenuList (CurrentMenu
, &Selection
->FormSetGuid
, Statement
->RefFormId
);
2607 Selection
->FormId
= Statement
->RefFormId
;
2608 Selection
->QuestionId
= Statement
->RefQuestionId
;
2609 } else if (Statement
->RefQuestionId
!= 0) {
2611 // Goto another Question
2613 Selection
->QuestionId
= Statement
->RefQuestionId
;
2615 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2616 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2625 case EFI_IFR_ACTION_OP
:
2627 // Process the Config string <ConfigResp>
2629 Status
= ProcessQuestionConfig (Selection
, Statement
);
2631 if (EFI_ERROR (Status
)) {
2636 // The action button may change some Question value, so refresh the form
2638 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2641 case EFI_IFR_RESET_BUTTON_OP
:
2643 // Reset Question to default value specified by DefaultId
2645 ControlFlag
= CfUiDefault
;
2646 DefaultId
= Statement
->DefaultId
;
2651 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2653 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2654 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2656 if (EFI_ERROR (Status
)) {
2659 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2661 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2664 if (OptionString
!= NULL
) {
2665 FreePool (OptionString
);
2673 // We come here when someone press ESC
2675 ControlFlag
= CfCheckSelection
;
2676 if (FindNextMenu (Selection
, &Repaint
, &NewLine
)) {
2682 ControlFlag
= CfCheckSelection
;
2683 ASSERT(MenuOption
!= NULL
);
2684 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2685 if (MenuOption
->Sequence
!= 0) {
2687 // In the middle or tail of the Date/Time op-code set, go left.
2689 ASSERT(NewPos
!= NULL
);
2690 NewPos
= NewPos
->BackLink
;
2696 ControlFlag
= CfCheckSelection
;
2697 ASSERT(MenuOption
!= NULL
);
2698 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2699 if (MenuOption
->Sequence
!= 2) {
2701 // In the middle or tail of the Date/Time op-code set, go left.
2703 ASSERT(NewPos
!= NULL
);
2704 NewPos
= NewPos
->ForwardLink
;
2710 ControlFlag
= CfCheckSelection
;
2712 SavedListEntry
= NewPos
;
2714 ASSERT(NewPos
!= NULL
);
2716 // Adjust Date/Time position before we advance forward.
2718 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2719 if (NewPos
->BackLink
!= &gMenuOption
) {
2720 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2722 NewPos
= NewPos
->BackLink
;
2724 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2725 DistanceValue
= PreviousMenuOption
->Skip
;
2727 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2728 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2730 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2732 ASSERT (MenuOption
!= NULL
);
2733 if (Difference
< 0) {
2735 // We hit the begining MenuOption that can be focused
2736 // so we simply scroll to the top.
2738 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2739 TopOfScreen
= gMenuOption
.ForwardLink
;
2743 // Scroll up to the last page when we have arrived at top page.
2745 NewPos
= &gMenuOption
;
2746 TopOfScreen
= &gMenuOption
;
2747 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2748 ScreenOperation
= UiPageUp
;
2749 ControlFlag
= CfScreenOperation
;
2752 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2754 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2756 TopOfScreen
= NewPos
;
2760 } else if (!IsSelectable (NextMenuOption
)) {
2762 // Continue to go up until scroll to next page or the selectable option is found.
2764 ScreenOperation
= UiUp
;
2765 ControlFlag
= CfScreenOperation
;
2769 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2771 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2772 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2773 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2774 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2777 // Scroll up to the last page.
2779 NewPos
= &gMenuOption
;
2780 TopOfScreen
= &gMenuOption
;
2781 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2782 ScreenOperation
= UiPageUp
;
2783 ControlFlag
= CfScreenOperation
;
2788 ControlFlag
= CfCheckSelection
;
2790 ASSERT(NewPos
!= NULL
);
2791 if (NewPos
->BackLink
== &gMenuOption
) {
2801 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2802 Link
= Link
->BackLink
;
2803 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2804 if (Index
< PreviousMenuOption
->Skip
) {
2808 Index
= Index
- PreviousMenuOption
->Skip
;
2811 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2812 if (TopOfScreen
== &gMenuOption
) {
2813 TopOfScreen
= gMenuOption
.ForwardLink
;
2814 NewPos
= gMenuOption
.BackLink
;
2815 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2817 } else if (TopOfScreen
!= Link
) {
2820 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2823 // Finally we know that NewPos is the last MenuOption can be focused.
2827 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2830 if (Index
+ 1 < TopRow
) {
2832 // Back up the previous option.
2834 Link
= Link
->ForwardLink
;
2838 // Move to the option in Next page.
2840 if (TopOfScreen
== &gMenuOption
) {
2841 NewPos
= gMenuOption
.BackLink
;
2842 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2845 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2849 // There are more MenuOption needing scrolling up.
2856 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2857 // Don't do this when we are already in the first page.
2859 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2860 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2864 ControlFlag
= CfCheckSelection
;
2866 ASSERT (NewPos
!= NULL
);
2867 if (NewPos
->ForwardLink
== &gMenuOption
) {
2876 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2878 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
2879 Index
= Index
+ NextMenuOption
->Skip
;
2880 Link
= Link
->ForwardLink
;
2881 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2884 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
2886 // Finally we know that NewPos is the last MenuOption can be focused.
2889 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2891 if (Index
- 1 > BottomRow
) {
2893 // Back up the previous option.
2895 Link
= Link
->BackLink
;
2898 // There are more MenuOption needing scrolling down.
2903 // Move to the option in Next page.
2905 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
2909 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2910 // Don't do this when we are already in the last page.
2913 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2914 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2918 ControlFlag
= CfCheckSelection
;
2920 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2921 // to be one that progresses to the next set of op-codes, we need to advance to the last
2922 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2923 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2924 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2925 // the Date/Time op-code.
2927 SavedListEntry
= NewPos
;
2928 AdjustDateAndTimePosition (FALSE
, &NewPos
);
2930 if (NewPos
->ForwardLink
!= &gMenuOption
) {
2931 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2933 NewPos
= NewPos
->ForwardLink
;
2936 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
2937 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
2939 // We hit the end of MenuOption that can be focused
2940 // so we simply scroll to the first page.
2942 if (Difference
< 0) {
2944 // Scroll to the first page.
2946 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2947 TopOfScreen
= gMenuOption
.ForwardLink
;
2951 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2953 NewPos
= gMenuOption
.ForwardLink
;
2954 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2957 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2959 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2960 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2964 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2967 // An option might be multi-line, so we need to reflect that data in the overall skip value
2969 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
2970 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
2972 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
2973 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
2974 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
2975 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2981 // If we are going to scroll, update TopOfScreen
2983 if (Temp
> BottomRow
) {
2986 // Is the current top of screen a zero-advance op-code?
2987 // If so, keep moving forward till we hit a >0 advance op-code
2989 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2992 // If bottom op-code is more than one line or top op-code is more than one line
2994 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
2996 // Is the bottom op-code greater than or equal in size to the top op-code?
2998 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3000 // Skip the top op-code
3002 TopOfScreen
= TopOfScreen
->ForwardLink
;
3003 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3005 OldSkipValue
= Difference
;
3007 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3010 // If we have a remainder, skip that many more op-codes until we drain the remainder
3012 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3014 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3016 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3017 TopOfScreen
= TopOfScreen
->ForwardLink
;
3018 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3021 // Since we will act on this op-code in the next routine, and increment the
3022 // SkipValue, set the skips to one less than what is required.
3024 SkipValue
= Difference
- 1;
3028 // Since we will act on this op-code in the next routine, and increment the
3029 // SkipValue, set the skips to one less than what is required.
3031 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3034 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3035 TopOfScreen
= TopOfScreen
->ForwardLink
;
3038 SkipValue
= OldSkipValue
;
3042 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3043 // Let's set a skip flag to smoothly scroll the top of the screen.
3045 if (SavedMenuOption
->Skip
> 1) {
3046 if (SavedMenuOption
== NextMenuOption
) {
3051 } else if (SavedMenuOption
->Skip
== 1) {
3055 TopOfScreen
= TopOfScreen
->ForwardLink
;
3057 } while (SavedMenuOption
->Skip
== 0);
3060 OldSkipValue
= SkipValue
;
3061 } else if (!IsSelectable (NextMenuOption
)) {
3063 // Continue to go down until scroll to next page or the selectable option is found.
3065 ScreenOperation
= UiDown
;
3066 ControlFlag
= CfScreenOperation
;
3069 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3071 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3075 // Scroll to the first page.
3077 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3078 TopOfScreen
= gMenuOption
.ForwardLink
;
3082 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3085 NewPos
= gMenuOption
.ForwardLink
;
3086 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3090 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3092 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3093 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3097 ControlFlag
= CfCheckSelection
;
3102 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, FALSE
);
3104 if (!EFI_ERROR (Status
)) {
3105 ASSERT(MenuOption
!= NULL
);
3106 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3107 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3110 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3111 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3119 ControlFlag
= CfCheckSelection
;
3120 if (!Selection
->FormEditable
) {
3122 // This Form is not editable, ignore the F9 (reset to default)
3127 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3129 if (!EFI_ERROR (Status
)) {
3130 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3131 Selection
->Statement
= NULL
;
3134 // Show NV update flag on status bar
3136 UpdateNvInfoInForm(Selection
->FormSet
, TRUE
);
3137 gResetRequired
= TRUE
;
3141 case CfUiNoOperation
:
3142 ControlFlag
= CfCheckSelection
;
3146 UiFreeRefreshList ();
3148 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3149 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3150 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3151 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");