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
;
1651 UINTN ModalSkipColumn
;
1653 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1655 Status
= EFI_SUCCESS
;
1656 FormattedString
= NULL
;
1657 OptionString
= NULL
;
1658 ScreenOperation
= UiNoOperation
;
1660 MinRefreshInterval
= 0;
1663 OutputString
= NULL
;
1668 MenuRefreshEntry
= gMenuRefreshHead
;
1670 NextMenuOption
= NULL
;
1671 PreviousMenuOption
= NULL
;
1672 SavedMenuOption
= NULL
;
1674 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
1676 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1678 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1679 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1680 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1682 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1683 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1686 if (Selection
->Form
->ModalForm
) {
1687 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1689 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1692 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1694 Selection
->TopRow
= TopRow
;
1695 Selection
->BottomRow
= BottomRow
;
1696 Selection
->PromptCol
= Col
;
1697 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1698 Selection
->Statement
= NULL
;
1700 TopOfScreen
= gMenuOption
.ForwardLink
;
1705 // Find current Menu
1707 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1708 if (CurrentMenu
== NULL
) {
1710 // Current menu not found, add it to the menu tree
1712 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1714 ASSERT (CurrentMenu
!= NULL
);
1715 Selection
->CurrentMenu
= CurrentMenu
;
1717 if (Selection
->QuestionId
== 0) {
1719 // Highlight not specified, fetch it from cached menu
1721 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1725 // Init option as the current user's selection
1727 InitializedFlag
= TRUE
;
1728 NewPos
= gMenuOption
.ForwardLink
;
1730 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1731 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1733 ControlFlag
= CfInitialization
;
1734 Selection
->Action
= UI_ACTION_NONE
;
1736 switch (ControlFlag
) {
1737 case CfInitialization
:
1738 if (IsListEmpty (&gMenuOption
)) {
1739 ControlFlag
= CfReadKey
;
1741 ControlFlag
= CfCheckSelection
;
1745 case CfCheckSelection
:
1746 if (Selection
->Action
!= UI_ACTION_NONE
) {
1747 ControlFlag
= CfExit
;
1749 ControlFlag
= CfRepaint
;
1754 ControlFlag
= CfRefreshHighLight
;
1764 Temp
= (UINTN
) SkipValue
;
1765 Temp2
= (UINTN
) SkipValue
;
1767 if (Selection
->Form
->ModalForm
) {
1769 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
1770 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1771 TopRow
- SCROLL_ARROW_HEIGHT
,
1772 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1773 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1777 LocalScreen
.LeftColumn
,
1778 LocalScreen
.RightColumn
,
1779 TopRow
- SCROLL_ARROW_HEIGHT
,
1780 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1781 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1784 UiFreeRefreshList ();
1785 MinRefreshInterval
= 0;
1787 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1788 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1789 MenuOption
->Row
= Row
;
1790 MenuOption
->Col
= Col
;
1791 if (Selection
->Form
->ModalForm
) {
1792 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
1794 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1797 Statement
= MenuOption
->ThisTag
;
1798 if (Statement
->InSubtitle
) {
1799 MenuOption
->Col
+= SUBTITLE_INDENT
;
1802 if (MenuOption
->GrayOut
) {
1803 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1805 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1806 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
1810 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1813 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1815 // Print Arrow for Goto button.
1818 MenuOption
->Col
- 2,
1821 GEOMETRICSHAPE_RIGHT_TRIANGLE
1825 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1826 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1827 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1830 // If there is more string to process print on the next row and increment the Skip value
1832 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1838 FreePool (OutputString
);
1847 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1848 if (EFI_ERROR (Status
)) {
1850 // Repaint to clear possible error prompt pop-up
1854 ControlFlag
= CfRepaint
;
1858 if (OptionString
!= NULL
) {
1859 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1861 // If leading spaces on OptionString - remove the spaces
1863 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1864 MenuOption
->OptCol
++;
1867 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1868 OptionString
[Count
] = OptionString
[Index
];
1872 OptionString
[Count
] = CHAR_NULL
;
1876 // If Question request refresh, register the op-code
1878 if (Statement
->RefreshInterval
!= 0) {
1880 // Menu will be refreshed at minimal interval of all Questions
1881 // which have refresh request
1883 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1884 MinRefreshInterval
= Statement
->RefreshInterval
;
1887 if (gMenuRefreshHead
== NULL
) {
1888 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1889 ASSERT (MenuRefreshEntry
!= NULL
);
1890 MenuRefreshEntry
->MenuOption
= MenuOption
;
1891 MenuRefreshEntry
->Selection
= Selection
;
1892 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1893 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1894 if (MenuOption
->GrayOut
) {
1895 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1897 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1899 gMenuRefreshHead
= MenuRefreshEntry
;
1902 // Advance to the last entry
1904 for (MenuRefreshEntry
= gMenuRefreshHead
;
1905 MenuRefreshEntry
->Next
!= NULL
;
1906 MenuRefreshEntry
= MenuRefreshEntry
->Next
1909 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1910 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1911 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1912 MenuRefreshEntry
->MenuOption
= MenuOption
;
1913 MenuRefreshEntry
->Selection
= Selection
;
1914 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1915 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1916 if (MenuOption
->GrayOut
) {
1917 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1919 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1924 Width
= (UINT16
) gOptionBlockWidth
;
1927 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1928 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1929 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1932 // If there is more string to process print on the next row and increment the Skip value
1934 if (StrLen (&OptionString
[Index
]) != 0) {
1938 // Since the Number of lines for this menu entry may or may not be reflected accurately
1939 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1940 // some testing to ensure we are keeping this in-sync.
1942 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1944 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1950 FreePool (OutputString
);
1959 FreePool (OptionString
);
1962 // If this is a text op with secondary text information
1964 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1965 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
1967 Width
= (UINT16
) gOptionBlockWidth
;
1970 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1971 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1972 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1975 // If there is more string to process print on the next row and increment the Skip value
1977 if (StrLen (&StringPtr
[Index
]) != 0) {
1981 // Since the Number of lines for this menu entry may or may not be reflected accurately
1982 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1983 // some testing to ensure we are keeping this in-sync.
1985 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1987 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1993 FreePool (OutputString
);
2000 FreePool (StringPtr
);
2002 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2005 // Need to handle the bottom of the display
2007 if (MenuOption
->Skip
> 1) {
2008 Row
+= MenuOption
->Skip
- SkipValue
;
2011 Row
+= MenuOption
->Skip
;
2014 if (Row
> BottomRow
) {
2015 if (!ValueIsScroll (FALSE
, Link
)) {
2019 Row
= BottomRow
+ 1;
2024 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2029 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2031 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2032 TopRow
- SCROLL_ARROW_HEIGHT
,
2036 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2040 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2042 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2043 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2047 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2054 case CfRefreshHighLight
:
2056 // MenuOption: Last menu option that need to remove hilight
2057 // MenuOption is set to NULL in Repaint
2058 // NewPos: Current menu option that need to hilight
2060 ControlFlag
= CfUpdateHelpString
;
2061 if (InitializedFlag
) {
2062 InitializedFlag
= FALSE
;
2063 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2067 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2068 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2070 SavedValue
= Repaint
;
2073 if (Selection
->QuestionId
!= 0) {
2074 NewPos
= gMenuOption
.ForwardLink
;
2075 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2077 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &gMenuOption
) {
2078 NewPos
= NewPos
->ForwardLink
;
2079 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2081 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2083 // Target Question found, find its MenuOption
2087 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2088 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2089 Index
+= SavedMenuOption
->Skip
;
2090 Link
= Link
->ForwardLink
;
2093 if (Link
!= NewPos
|| Index
> BottomRow
) {
2095 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2098 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2099 Link
= Link
->BackLink
;
2100 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2101 Index
+= SavedMenuOption
->Skip
;
2103 TopOfScreen
= Link
->ForwardLink
;
2107 ControlFlag
= CfRepaint
;
2112 // Target Question not found, highlight the default menu option
2114 NewPos
= TopOfScreen
;
2117 Selection
->QuestionId
= 0;
2120 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2121 if (MenuOption
!= NULL
) {
2123 // Remove highlight on last Menu Option
2125 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2126 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2127 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2128 if (OptionString
!= NULL
) {
2129 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2130 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2133 // If leading spaces on OptionString - remove the spaces
2135 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2138 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2139 OptionString
[Count
] = OptionString
[Index
];
2143 OptionString
[Count
] = CHAR_NULL
;
2146 Width
= (UINT16
) gOptionBlockWidth
;
2147 OriginalRow
= MenuOption
->Row
;
2149 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2150 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2151 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2154 // If there is more string to process print on the next row and increment the Skip value
2156 if (StrLen (&OptionString
[Index
]) != 0) {
2160 FreePool (OutputString
);
2163 MenuOption
->Row
= OriginalRow
;
2165 FreePool (OptionString
);
2168 if (MenuOption
->GrayOut
) {
2169 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2170 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2171 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2174 OriginalRow
= MenuOption
->Row
;
2175 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2177 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2178 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2179 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2182 // If there is more string to process print on the next row and increment the Skip value
2184 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2188 FreePool (OutputString
);
2191 MenuOption
->Row
= OriginalRow
;
2192 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2198 // This is the current selected statement
2200 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2201 Statement
= MenuOption
->ThisTag
;
2202 Selection
->Statement
= Statement
;
2203 if (!IsSelectable (MenuOption
)) {
2204 Repaint
= SavedValue
;
2205 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2210 // Record highlight for current menu
2212 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2215 // Set reverse attribute
2217 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2218 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2221 // Assuming that we have a refresh linked-list created, lets annotate the
2222 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2223 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2225 if (gMenuRefreshHead
!= NULL
) {
2226 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2227 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2228 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2230 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2232 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2233 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2238 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2239 if (OptionString
!= NULL
) {
2240 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2242 // If leading spaces on OptionString - remove the spaces
2244 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2247 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2248 OptionString
[Count
] = OptionString
[Index
];
2252 OptionString
[Count
] = CHAR_NULL
;
2254 Width
= (UINT16
) gOptionBlockWidth
;
2256 OriginalRow
= MenuOption
->Row
;
2258 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2259 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2260 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2263 // If there is more string to process print on the next row and increment the Skip value
2265 if (StrLen (&OptionString
[Index
]) != 0) {
2269 FreePool (OutputString
);
2272 MenuOption
->Row
= OriginalRow
;
2274 FreePool (OptionString
);
2277 OriginalRow
= MenuOption
->Row
;
2279 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2281 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2282 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2283 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2286 // If there is more string to process print on the next row and increment the Skip value
2288 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2292 FreePool (OutputString
);
2295 MenuOption
->Row
= OriginalRow
;
2300 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2303 // Clear reverse attribute
2305 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2308 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2309 // if we didn't break halfway when process CfRefreshHighLight.
2311 Repaint
= SavedValue
;
2314 case CfUpdateHelpString
:
2315 ControlFlag
= CfPrepareToReadKey
;
2316 if (Selection
->Form
->ModalForm
) {
2320 if (Repaint
|| NewLine
) {
2322 // Don't print anything if it is a NULL help token
2324 ASSERT(MenuOption
!= NULL
);
2325 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2328 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2331 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2333 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2335 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2337 // Pad String with spaces to simulate a clearing of the previous line
2339 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2340 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2344 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2346 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2351 // Reset this flag every time we finish using it.
2357 case CfPrepareToReadKey
:
2358 ControlFlag
= CfReadKey
;
2359 ScreenOperation
= UiNoOperation
;
2363 ControlFlag
= CfScreenOperation
;
2366 // Wait for user's selection
2369 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2370 } while (Status
== EFI_TIMEOUT
);
2372 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2374 // IFR is updated in Callback of refresh opcode, re-parse it
2376 Selection
->Statement
= NULL
;
2380 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2382 // If we encounter error, continue to read another key in.
2384 if (EFI_ERROR (Status
)) {
2385 ControlFlag
= CfReadKey
;
2389 switch (Key
.UnicodeChar
) {
2390 case CHAR_CARRIAGE_RETURN
:
2391 ScreenOperation
= UiSelect
;
2396 // We will push the adjustment of these numeric values directly to the input handler
2397 // NOTE: we won't handle manual input numeric
2402 // If the screen has no menu items, and the user didn't select UiReset
2403 // ignore the selection and go back to reading keys.
2405 if(IsListEmpty (&gMenuOption
)) {
2406 ControlFlag
= CfReadKey
;
2410 ASSERT(MenuOption
!= NULL
);
2411 Statement
= MenuOption
->ThisTag
;
2412 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2413 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2414 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2416 if (Key
.UnicodeChar
== '+') {
2417 gDirection
= SCAN_RIGHT
;
2419 gDirection
= SCAN_LEFT
;
2421 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2422 if (EFI_ERROR (Status
)) {
2424 // Repaint to clear possible error prompt pop-up
2429 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2431 if (OptionString
!= NULL
) {
2432 FreePool (OptionString
);
2438 ScreenOperation
= UiUp
;
2443 ScreenOperation
= UiDown
;
2447 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2449 // If the screen has no menu items, and the user didn't select UiReset
2450 // ignore the selection and go back to reading keys.
2452 if(IsListEmpty (&gMenuOption
)) {
2453 ControlFlag
= CfReadKey
;
2457 ASSERT(MenuOption
!= NULL
);
2458 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2459 ScreenOperation
= UiSelect
;
2465 if (((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2466 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2469 // If the function key has been disabled, just ignore the key.
2472 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2473 if (Selection
->Form
->ModalForm
&&
2474 (Key
.ScanCode
== SCAN_F9
|| Key
.ScanCode
== SCAN_F10
|| Key
.ScanCode
== SCAN_ESC
)) {
2475 ControlFlag
= CfReadKey
;
2479 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2480 if (Key
.ScanCode
== SCAN_F9
) {
2482 // Reset to standard default
2484 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2486 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2495 case CfScreenOperation
:
2496 if (ScreenOperation
!= UiReset
) {
2498 // If the screen has no menu items, and the user didn't select UiReset
2499 // ignore the selection and go back to reading keys.
2501 if (IsListEmpty (&gMenuOption
)) {
2502 ControlFlag
= CfReadKey
;
2508 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2511 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2512 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2519 ControlFlag
= CfCheckSelection
;
2521 ASSERT(MenuOption
!= NULL
);
2522 Statement
= MenuOption
->ThisTag
;
2523 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2528 // Keep highlight on current MenuOption
2530 Selection
->QuestionId
= Statement
->QuestionId
;
2532 switch (Statement
->Operand
) {
2533 case EFI_IFR_REF_OP
:
2534 if (Statement
->RefDevicePath
!= 0) {
2535 if (Selection
->Form
->ModalForm
) {
2539 // Goto another Hii Package list
2541 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2543 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2544 if (StringPtr
== NULL
) {
2546 // No device path string not found, exit
2548 Selection
->Action
= UI_ACTION_EXIT
;
2549 Selection
->Statement
= NULL
;
2552 BufferSize
= StrLen (StringPtr
) / 2;
2553 DevicePath
= AllocatePool (BufferSize
);
2554 ASSERT (DevicePath
!= NULL
);
2557 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2559 DevicePathBuffer
= (UINT8
*) DevicePath
;
2560 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2561 TemStr
[0] = StringPtr
[Index
];
2562 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2563 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2565 // Invalid Hex Char as the tail.
2569 if ((Index
& 1) == 0) {
2570 DevicePathBuffer
[Index
/2] = DigitUint8
;
2572 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2576 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2577 if (Selection
->Handle
== NULL
) {
2579 // If target Hii Handle not found, exit
2581 Selection
->Action
= UI_ACTION_EXIT
;
2582 Selection
->Statement
= NULL
;
2586 FreePool (StringPtr
);
2587 FreePool (DevicePath
);
2589 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2590 Selection
->FormId
= Statement
->RefFormId
;
2591 Selection
->QuestionId
= Statement
->RefQuestionId
;
2592 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2593 if (Selection
->Form
->ModalForm
) {
2597 // Goto another Formset, check for uncommitted data
2599 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2601 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2602 Selection
->FormId
= Statement
->RefFormId
;
2603 Selection
->QuestionId
= Statement
->RefQuestionId
;
2604 } else if (Statement
->RefFormId
!= 0) {
2606 // Check whether target From is suppressed.
2608 RefForm
= IdToForm (Selection
->FormSet
, Statement
->RefFormId
);
2610 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2611 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
2612 if (EFI_ERROR (Status
)) {
2616 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
2618 // Form is suppressed.
2621 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2622 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2630 // Goto another form inside this formset,
2632 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2635 // Link current form so that we can always go back when someone hits the ESC
2637 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->RefFormId
);
2638 if (MenuList
== NULL
) {
2639 MenuList
= UiAddMenuList (CurrentMenu
, &Selection
->FormSetGuid
, Statement
->RefFormId
);
2642 Selection
->FormId
= Statement
->RefFormId
;
2643 Selection
->QuestionId
= Statement
->RefQuestionId
;
2644 } else if (Statement
->RefQuestionId
!= 0) {
2646 // Goto another Question
2648 Selection
->QuestionId
= Statement
->RefQuestionId
;
2650 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2651 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2660 case EFI_IFR_ACTION_OP
:
2662 // Process the Config string <ConfigResp>
2664 Status
= ProcessQuestionConfig (Selection
, Statement
);
2666 if (EFI_ERROR (Status
)) {
2671 // The action button may change some Question value, so refresh the form
2673 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2676 case EFI_IFR_RESET_BUTTON_OP
:
2678 // Reset Question to default value specified by DefaultId
2680 ControlFlag
= CfUiDefault
;
2681 DefaultId
= Statement
->DefaultId
;
2686 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2688 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2689 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2691 if (EFI_ERROR (Status
)) {
2694 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2696 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2699 if (OptionString
!= NULL
) {
2700 FreePool (OptionString
);
2708 // We come here when someone press ESC
2710 ControlFlag
= CfCheckSelection
;
2711 if (FindNextMenu (Selection
, &Repaint
, &NewLine
)) {
2717 ControlFlag
= CfCheckSelection
;
2718 ASSERT(MenuOption
!= NULL
);
2719 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2720 if (MenuOption
->Sequence
!= 0) {
2722 // In the middle or tail of the Date/Time op-code set, go left.
2724 ASSERT(NewPos
!= NULL
);
2725 NewPos
= NewPos
->BackLink
;
2731 ControlFlag
= CfCheckSelection
;
2732 ASSERT(MenuOption
!= NULL
);
2733 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2734 if (MenuOption
->Sequence
!= 2) {
2736 // In the middle or tail of the Date/Time op-code set, go left.
2738 ASSERT(NewPos
!= NULL
);
2739 NewPos
= NewPos
->ForwardLink
;
2745 ControlFlag
= CfCheckSelection
;
2747 SavedListEntry
= NewPos
;
2749 ASSERT(NewPos
!= NULL
);
2751 // Adjust Date/Time position before we advance forward.
2753 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2754 if (NewPos
->BackLink
!= &gMenuOption
) {
2755 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2757 NewPos
= NewPos
->BackLink
;
2759 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2760 DistanceValue
= PreviousMenuOption
->Skip
;
2762 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2763 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2765 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2767 ASSERT (MenuOption
!= NULL
);
2768 if (Difference
< 0) {
2770 // We hit the begining MenuOption that can be focused
2771 // so we simply scroll to the top.
2773 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2774 TopOfScreen
= gMenuOption
.ForwardLink
;
2778 // Scroll up to the last page when we have arrived at top page.
2780 NewPos
= &gMenuOption
;
2781 TopOfScreen
= &gMenuOption
;
2782 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2783 ScreenOperation
= UiPageUp
;
2784 ControlFlag
= CfScreenOperation
;
2787 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2789 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2791 TopOfScreen
= NewPos
;
2795 } else if (!IsSelectable (NextMenuOption
)) {
2797 // Continue to go up until scroll to next page or the selectable option is found.
2799 ScreenOperation
= UiUp
;
2800 ControlFlag
= CfScreenOperation
;
2804 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2806 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2807 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2808 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2809 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2812 // Scroll up to the last page.
2814 NewPos
= &gMenuOption
;
2815 TopOfScreen
= &gMenuOption
;
2816 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2817 ScreenOperation
= UiPageUp
;
2818 ControlFlag
= CfScreenOperation
;
2823 ControlFlag
= CfCheckSelection
;
2825 ASSERT(NewPos
!= NULL
);
2826 if (NewPos
->BackLink
== &gMenuOption
) {
2836 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2837 Link
= Link
->BackLink
;
2838 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2839 if (Index
< PreviousMenuOption
->Skip
) {
2843 Index
= Index
- PreviousMenuOption
->Skip
;
2846 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2847 if (TopOfScreen
== &gMenuOption
) {
2848 TopOfScreen
= gMenuOption
.ForwardLink
;
2849 NewPos
= gMenuOption
.BackLink
;
2850 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2852 } else if (TopOfScreen
!= Link
) {
2855 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2858 // Finally we know that NewPos is the last MenuOption can be focused.
2862 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2865 if (Index
+ 1 < TopRow
) {
2867 // Back up the previous option.
2869 Link
= Link
->ForwardLink
;
2873 // Move to the option in Next page.
2875 if (TopOfScreen
== &gMenuOption
) {
2876 NewPos
= gMenuOption
.BackLink
;
2877 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2880 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2884 // There are more MenuOption needing scrolling up.
2891 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2892 // Don't do this when we are already in the first page.
2894 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2895 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2899 ControlFlag
= CfCheckSelection
;
2901 ASSERT (NewPos
!= NULL
);
2902 if (NewPos
->ForwardLink
== &gMenuOption
) {
2911 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2913 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
2914 Index
= Index
+ NextMenuOption
->Skip
;
2915 Link
= Link
->ForwardLink
;
2916 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2919 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
2921 // Finally we know that NewPos is the last MenuOption can be focused.
2924 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2926 if (Index
- 1 > BottomRow
) {
2928 // Back up the previous option.
2930 Link
= Link
->BackLink
;
2933 // There are more MenuOption needing scrolling down.
2938 // Move to the option in Next page.
2940 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
2944 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2945 // Don't do this when we are already in the last page.
2948 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2949 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2953 ControlFlag
= CfCheckSelection
;
2955 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2956 // to be one that progresses to the next set of op-codes, we need to advance to the last
2957 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2958 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2959 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2960 // the Date/Time op-code.
2962 SavedListEntry
= NewPos
;
2963 AdjustDateAndTimePosition (FALSE
, &NewPos
);
2965 if (NewPos
->ForwardLink
!= &gMenuOption
) {
2966 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2968 NewPos
= NewPos
->ForwardLink
;
2971 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
2972 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
2974 // We hit the end of MenuOption that can be focused
2975 // so we simply scroll to the first page.
2977 if (Difference
< 0) {
2979 // Scroll to the first page.
2981 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2982 TopOfScreen
= gMenuOption
.ForwardLink
;
2986 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2988 NewPos
= gMenuOption
.ForwardLink
;
2989 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2992 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2994 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2995 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2999 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3002 // An option might be multi-line, so we need to reflect that data in the overall skip value
3004 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
3005 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3007 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3008 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3009 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3010 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3016 // If we are going to scroll, update TopOfScreen
3018 if (Temp
> BottomRow
) {
3021 // Is the current top of screen a zero-advance op-code?
3022 // If so, keep moving forward till we hit a >0 advance op-code
3024 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3027 // If bottom op-code is more than one line or top op-code is more than one line
3029 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3031 // Is the bottom op-code greater than or equal in size to the top op-code?
3033 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3035 // Skip the top op-code
3037 TopOfScreen
= TopOfScreen
->ForwardLink
;
3038 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3040 OldSkipValue
= Difference
;
3042 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3045 // If we have a remainder, skip that many more op-codes until we drain the remainder
3047 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3049 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3051 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3052 TopOfScreen
= TopOfScreen
->ForwardLink
;
3053 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3056 // Since we will act on this op-code in the next routine, and increment the
3057 // SkipValue, set the skips to one less than what is required.
3059 SkipValue
= Difference
- 1;
3063 // Since we will act on this op-code in the next routine, and increment the
3064 // SkipValue, set the skips to one less than what is required.
3066 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3069 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3070 TopOfScreen
= TopOfScreen
->ForwardLink
;
3073 SkipValue
= OldSkipValue
;
3077 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3078 // Let's set a skip flag to smoothly scroll the top of the screen.
3080 if (SavedMenuOption
->Skip
> 1) {
3081 if (SavedMenuOption
== NextMenuOption
) {
3086 } else if (SavedMenuOption
->Skip
== 1) {
3090 TopOfScreen
= TopOfScreen
->ForwardLink
;
3092 } while (SavedMenuOption
->Skip
== 0);
3095 OldSkipValue
= SkipValue
;
3096 } else if (!IsSelectable (NextMenuOption
)) {
3098 // Continue to go down until scroll to next page or the selectable option is found.
3100 ScreenOperation
= UiDown
;
3101 ControlFlag
= CfScreenOperation
;
3104 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3106 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3110 // Scroll to the first page.
3112 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3113 TopOfScreen
= gMenuOption
.ForwardLink
;
3117 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3120 NewPos
= gMenuOption
.ForwardLink
;
3121 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3125 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3127 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3128 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3132 ControlFlag
= CfCheckSelection
;
3137 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, FALSE
);
3139 if (!EFI_ERROR (Status
)) {
3140 ASSERT(MenuOption
!= NULL
);
3141 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3142 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3145 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3146 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3154 ControlFlag
= CfCheckSelection
;
3155 if (!Selection
->FormEditable
) {
3157 // This Form is not editable, ignore the F9 (reset to default)
3162 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3164 if (!EFI_ERROR (Status
)) {
3165 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3166 Selection
->Statement
= NULL
;
3169 // Show NV update flag on status bar
3171 UpdateNvInfoInForm(Selection
->FormSet
, TRUE
);
3172 gResetRequired
= TRUE
;
3176 case CfUiNoOperation
:
3177 ControlFlag
= CfCheckSelection
;
3181 UiFreeRefreshList ();
3183 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3184 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3185 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3186 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");