2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2008, Intel Corporation
5 All rights reserved. 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.
20 MENU_REFRESH_ENTRY
*gMenuRefreshHead
;
23 // Search table for UiDisplayMenu()
25 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
68 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
120 BOOLEAN GetLineByWidthFinished
= FALSE
;
124 Set Buffer to Value for Size bytes.
126 @param Buffer Memory to set.
127 @param Size Number of bytes to set
128 @param Value Value of the set operation.
143 while ((Size
--) != 0) {
150 Initialize Menu option list.
158 InitializeListHead (&Menu
);
163 Initialize Menu option list.
171 InitializeListHead (&gMenuList
);
176 Remove a Menu in list, and return FormId/QuestionId for previous Menu.
178 @param Selection Menu selection.
182 UiRemoveMenuListEntry (
183 OUT UI_MENU_SELECTION
*Selection
186 UI_MENU_LIST
*UiMenuList
;
188 if (!IsListEmpty (&gMenuList
)) {
189 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
191 Selection
->FormId
= UiMenuList
->FormId
;
192 Selection
->QuestionId
= UiMenuList
->QuestionId
;
193 RemoveEntryList (&UiMenuList
->MenuLink
);
194 FreePool (UiMenuList
);
200 Free Menu option linked list.
208 UI_MENU_LIST
*UiMenuList
;
210 while (!IsListEmpty (&gMenuList
)) {
211 UiMenuList
= CR (gMenuList
.ForwardLink
, UI_MENU_LIST
, MenuLink
, UI_MENU_LIST_SIGNATURE
);
212 RemoveEntryList (&UiMenuList
->MenuLink
);
213 FreePool (UiMenuList
);
219 Add one menu entry to the linked lst
221 @param Selection Menu selection.
226 IN UI_MENU_SELECTION
*Selection
229 UI_MENU_LIST
*UiMenuList
;
231 UiMenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
232 ASSERT (UiMenuList
!= NULL
);
234 UiMenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
235 UiMenuList
->FormId
= Selection
->FormId
;
236 UiMenuList
->QuestionId
= Selection
->QuestionId
;
238 InsertHeadList (&gMenuList
, &UiMenuList
->MenuLink
);
243 Free Menu option linked list.
251 UI_MENU_OPTION
*MenuOption
;
253 while (!IsListEmpty (&Menu
)) {
254 MenuOption
= MENU_OPTION_FROM_LINK (Menu
.ForwardLink
);
255 RemoveEntryList (&MenuOption
->Link
);
258 // We allocated space for this description when we did a GetToken, free it here
260 if (MenuOption
->Skip
!= 0) {
262 // For date/time, MenuOption->Description is shared by three Menu Options
263 // Data format : [01/02/2004] [11:22:33]
264 // Line number : 0 0 1 0 0 1
266 FreePool (MenuOption
->Description
);
268 FreePool (MenuOption
);
274 Free Menu option linked list.
282 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
284 while (gMenuRefreshHead
!= NULL
) {
285 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
286 FreePool (gMenuRefreshHead
);
287 gMenuRefreshHead
= OldMenuRefreshEntry
;
290 gMenuRefreshHead
= NULL
;
304 CHAR16
*OptionString
;
305 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
308 UI_MENU_SELECTION
*Selection
;
309 FORM_BROWSER_STATEMENT
*Question
;
310 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
311 EFI_HII_VALUE
*HiiValue
;
312 EFI_BROWSER_ACTION_REQUEST ActionRequest
;
314 if (gMenuRefreshHead
!= NULL
) {
316 MenuRefreshEntry
= gMenuRefreshHead
;
319 // Reset FormPackage update flag
321 mHiiPackageListUpdated
= FALSE
;
324 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
326 Selection
= MenuRefreshEntry
->Selection
;
327 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
329 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
330 if (EFI_ERROR (Status
)) {
335 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
337 if (OptionString
!= NULL
) {
339 // If leading spaces on OptionString - remove the spaces
341 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
344 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
345 FreePool (OptionString
);
349 // Question value may be changed, need invoke its Callback()
351 ConfigAccess
= Selection
->FormSet
->ConfigAccess
;
352 if (((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) && (ConfigAccess
!= NULL
)) {
353 ActionRequest
= EFI_BROWSER_ACTION_REQUEST_NONE
;
355 HiiValue
= &Question
->HiiValue
;
356 if (HiiValue
->Type
== EFI_IFR_TYPE_STRING
) {
358 // Create String in HII database for Configuration Driver to retrieve
360 HiiValue
->Value
.string
= NewString ((CHAR16
*) Question
->BufferValue
, Selection
->FormSet
->HiiHandle
);
363 Status
= ConfigAccess
->Callback (
365 EFI_BROWSER_ACTION_CHANGING
,
366 Question
->QuestionId
,
372 if (HiiValue
->Type
== EFI_IFR_TYPE_STRING
) {
374 // Clean the String in HII Database
376 DeleteString (HiiValue
->Value
.string
, Selection
->FormSet
->HiiHandle
);
379 if (!EFI_ERROR (Status
)) {
380 switch (ActionRequest
) {
381 case EFI_BROWSER_ACTION_REQUEST_RESET
:
382 gResetRequired
= TRUE
;
385 case EFI_BROWSER_ACTION_REQUEST_SUBMIT
:
386 SubmitForm (Selection
->FormSet
, Selection
->Form
);
389 case EFI_BROWSER_ACTION_REQUEST_EXIT
:
390 Selection
->Action
= UI_ACTION_EXIT
;
391 gNvUpdateRequired
= FALSE
;
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.
531 IN EFI_HII_HANDLE Handle
,
532 IN FORM_BROWSER_STATEMENT
*Statement
,
533 IN UINT16 NumberOfLines
,
534 IN UINT16 MenuItemCount
537 UI_MENU_OPTION
*MenuOption
;
543 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
545 // Add three MenuOptions for Date/Time
546 // Data format : [01/02/2004] [11:22:33]
547 // Line number : 0 0 1 0 0 1
552 if (Statement
->Storage
== NULL
) {
554 // For RTC type of date/time, set default refresh interval to be 1 second
556 if (Statement
->RefreshInterval
== 0) {
557 Statement
->RefreshInterval
= 1;
562 for (Index
= 0; Index
< Count
; Index
++) {
563 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
566 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
567 MenuOption
->Description
= String
;
568 MenuOption
->Handle
= Handle
;
569 MenuOption
->ThisTag
= Statement
;
570 MenuOption
->EntryNumber
= MenuItemCount
;
574 // Override LineNumber for the MenuOption in Date/Time sequence
576 MenuOption
->Skip
= 1;
578 MenuOption
->Skip
= NumberOfLines
;
580 MenuOption
->Sequence
= Index
;
582 if (Statement
->GrayOutExpression
!= NULL
) {
583 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
586 if ((Statement
->ValueExpression
!= NULL
) ||
587 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
588 MenuOption
->ReadOnly
= TRUE
;
591 InsertTailList (&Menu
, &MenuOption
->Link
);
597 Routine used to abstract a generic dialog interface and return the selected key or string
599 @param NumberOfLines The number of lines for the dialog box
600 @param HotKey Defines whether a single character is parsed
601 (TRUE) and returned in KeyValue or a string is
602 returned in StringBuffer. Two special characters
603 are considered when entering a string, a SCAN_ESC
604 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
605 string input and returns
606 @param MaximumStringSize The maximum size in bytes of a typed in string
607 (each character is a CHAR16) and the minimum
608 string returned is two bytes
609 @param StringBuffer The passed in pointer to the buffer which will
610 hold the typed in string if HotKey is FALSE
611 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
612 @param ... A series of (quantity == NumberOfLines) text
613 strings which will be used to construct the dialog
616 @retval EFI_SUCCESS Displayed dialog and received user interaction
617 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
618 (StringBuffer == NULL) && (HotKey == FALSE))
619 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
624 IN UINTN NumberOfLines
,
626 IN UINTN MaximumStringSize
,
627 OUT CHAR16
*StringBuffer
,
628 OUT EFI_INPUT_KEY
*KeyValue
,
637 CHAR16
*BufferedString
;
644 BOOLEAN SelectionComplete
;
646 UINTN CurrentAttribute
;
647 UINTN DimensionsWidth
;
648 UINTN DimensionsHeight
;
650 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
651 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
653 SelectionComplete
= FALSE
;
655 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
656 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
657 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
660 ASSERT (BufferedString
);
662 VA_START (Marker
, KeyValue
);
665 // Zero the outgoing buffer
667 ZeroMem (StringBuffer
, MaximumStringSize
);
670 if (KeyValue
== NULL
) {
671 return EFI_INVALID_PARAMETER
;
674 if (StringBuffer
== NULL
) {
675 return EFI_INVALID_PARAMETER
;
681 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
686 // Determine the largest string in the dialog box
687 // Notice we are starting with 1 since String is the first string
689 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
690 StackString
= VA_ARG (Marker
, CHAR16
*);
692 if (StackString
[0] == L
' ') {
693 InputOffset
= Count
+ 1;
696 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
698 // Size of the string visually and subtract the width by one for the null-terminator
700 LargestString
= (GetStringWidth (StackString
) / 2);
705 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
706 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
713 VA_START (Marker
, KeyValue
);
714 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
718 // Take the first key typed and report it back?
721 Status
= WaitForKeyStroke (&Key
);
722 ASSERT_EFI_ERROR (Status
);
723 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
727 Status
= WaitForKeyStroke (&Key
);
729 switch (Key
.UnicodeChar
) {
731 switch (Key
.ScanCode
) {
733 FreePool (TempString
);
734 FreePool (BufferedString
);
735 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
736 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
737 return EFI_DEVICE_ERROR
;
745 case CHAR_CARRIAGE_RETURN
:
746 SelectionComplete
= TRUE
;
747 FreePool (TempString
);
748 FreePool (BufferedString
);
749 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
750 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
755 if (StringBuffer
[0] != CHAR_NULL
) {
756 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
757 TempString
[Index
] = StringBuffer
[Index
];
760 // Effectively truncate string by 1 character
762 TempString
[Index
- 1] = CHAR_NULL
;
763 StrCpy (StringBuffer
, TempString
);
768 // If it is the beginning of the string, don't worry about checking maximum limits
770 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
771 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
772 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
773 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
774 KeyPad
[0] = Key
.UnicodeChar
;
775 KeyPad
[1] = CHAR_NULL
;
776 StrCat (StringBuffer
, KeyPad
);
777 StrCat (TempString
, KeyPad
);
780 // If the width of the input string is now larger than the screen, we nee to
781 // adjust the index to start printing portions of the string
783 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
785 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
787 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
788 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
793 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
794 BufferedString
[Count
] = StringBuffer
[Index
];
797 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
800 } while (!SelectionComplete
);
803 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
804 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
809 Draw a pop up windows based on the dimension, number of lines and
812 @param RequestedWidth The width of the pop-up.
813 @param NumberOfLines The number of lines.
814 @param Marker The variable argument list for the list of string to be printed.
819 IN UINTN RequestedWidth
,
820 IN UINTN NumberOfLines
,
832 UINTN DimensionsWidth
;
833 UINTN DimensionsHeight
;
835 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
836 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
838 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
840 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
841 RequestedWidth
= DimensionsWidth
- 2;
845 // Subtract the PopUp width from total Columns, allow for one space extra on
846 // each end plus a border.
848 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
849 End
= Start
+ RequestedWidth
+ 1;
851 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
852 Bottom
= Top
+ NumberOfLines
+ 2;
854 Character
= BOXDRAW_DOWN_RIGHT
;
855 PrintCharAt (Start
, Top
, Character
);
856 Character
= BOXDRAW_HORIZONTAL
;
857 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
858 PrintChar (Character
);
861 Character
= BOXDRAW_DOWN_LEFT
;
862 PrintChar (Character
);
863 Character
= BOXDRAW_VERTICAL
;
866 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
867 String
= VA_ARG (Marker
, CHAR16
*);
870 // This will clear the background of the line - we never know who might have been
871 // here before us. This differs from the next clear in that it used the non-reverse
872 // video for normal printing.
874 if (GetStringWidth (String
) / 2 > 1) {
875 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
879 // Passing in a space results in the assumption that this is where typing will occur
881 if (String
[0] == L
' ') {
882 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
886 // Passing in a NULL results in a blank space
888 if (String
[0] == CHAR_NULL
) {
889 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
893 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
897 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
898 PrintCharAt (Start
, Index
+ 1, Character
);
899 PrintCharAt (End
- 1, Index
+ 1, Character
);
902 Character
= BOXDRAW_UP_RIGHT
;
903 PrintCharAt (Start
, Bottom
- 1, Character
);
904 Character
= BOXDRAW_HORIZONTAL
;
905 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
906 PrintChar (Character
);
909 Character
= BOXDRAW_UP_LEFT
;
910 PrintChar (Character
);
914 Draw a pop up windows based on the dimension, number of lines and
917 @param RequestedWidth The width of the pop-up.
918 @param NumberOfLines The number of lines.
919 @param ... A series of text strings that displayed in the pop-up.
923 CreateMultiStringPopUp (
924 IN UINTN RequestedWidth
,
925 IN UINTN NumberOfLines
,
931 VA_START (Marker
, NumberOfLines
);
933 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
940 Update status bar on the bottom of menu.
942 @param MessageType The type of message to be shown.
943 @param Flags The flags in Question header.
944 @param State Set or clear.
949 IN UINTN MessageType
,
955 CHAR16
*NvUpdateMessage
;
956 CHAR16
*InputErrorMessage
;
958 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
959 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
961 switch (MessageType
) {
964 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
966 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
967 gScreenDimensions
.BottomRow
- 1,
972 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
973 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
974 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
981 case NV_UPDATE_REQUIRED
:
982 if (gClassOfVfr
!= FORMSET_CLASS_FRONT_PAGE
) {
984 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
986 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
987 gScreenDimensions
.BottomRow
- 1,
990 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
992 gNvUpdateRequired
= TRUE
;
994 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
);
995 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
997 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
998 gScreenDimensions
.BottomRow
- 1,
1003 gNvUpdateRequired
= FALSE
;
1008 case REFRESH_STATUS_BAR
:
1010 UpdateStatusBar (INPUT_ERROR
, Flags
, TRUE
);
1013 if (gNvUpdateRequired
) {
1014 UpdateStatusBar (NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1022 FreePool (InputErrorMessage
);
1023 FreePool (NvUpdateMessage
);
1029 Get the supported width for a particular op-code
1031 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1032 @param Handle The handle in the HII database being used
1034 @return Returns the number of CHAR16 characters that is support.
1039 IN FORM_BROWSER_STATEMENT
*Statement
,
1040 IN EFI_HII_HANDLE Handle
1050 // See if the second text parameter is really NULL
1052 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1053 String
= GetToken (Statement
->TextTwo
, Handle
);
1054 Size
= StrLen (String
);
1058 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1059 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1060 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1061 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1062 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1064 // Allow a wide display if text op-code and no secondary text op-code
1066 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1068 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1070 Width
= (UINT16
) gPromptBlockWidth
;
1073 if (Statement
->InSubtitle
) {
1074 Width
-= SUBTITLE_INDENT
;
1081 Will copy LineWidth amount of a string in the OutputString buffer and return the
1082 number of CHAR16 characters that were copied into the OutputString buffer.
1084 @param InputString String description for this option.
1085 @param LineWidth Width of the desired string to extract in CHAR16
1087 @param Index Where in InputString to start the copy process
1088 @param OutputString Buffer to copy the string into
1090 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1095 IN CHAR16
*InputString
,
1096 IN UINT16 LineWidth
,
1097 IN OUT UINTN
*Index
,
1098 OUT CHAR16
**OutputString
1104 if (GetLineByWidthFinished
) {
1105 GetLineByWidthFinished
= FALSE
;
1112 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1115 // Ensure we have got a valid buffer
1117 if (*OutputString
!= NULL
) {
1120 //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.
1121 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1123 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1124 *Index
= *Index
+ 2;
1128 // Fast-forward the string and see if there is a carriage-return in the string
1130 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1134 // Copy the desired LineWidth of data to the output buffer.
1135 // Also make sure that we don't copy more than the string.
1136 // Also make sure that if there are linefeeds, we account for them.
1138 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1139 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1142 // Convert to CHAR16 value and show that we are done with this operation
1144 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1145 if (LineWidth
!= 0) {
1146 GetLineByWidthFinished
= TRUE
;
1149 if (Count2
== LineWidth
) {
1151 // Rewind the string from the maximum size until we see a space to break the line
1153 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1155 if (LineWidth
== 0) {
1163 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1166 // If currently pointing to a space, increment the index to the first non-space character
1169 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1173 *Index
= (UINT16
) (*Index
+ LineWidth
);
1182 Update display lines for a Menu Option.
1184 @param Selection The user's selection.
1185 @param MenuOption The MenuOption to be checked.
1186 @param OptionalString The option string.
1187 @param SkipValue The number of lins to skip.
1191 UpdateOptionSkipLines (
1192 IN UI_MENU_SELECTION
*Selection
,
1193 IN UI_MENU_OPTION
*MenuOption
,
1194 OUT CHAR16
**OptionalString
,
1202 CHAR16
*OutputString
;
1203 CHAR16
*OptionString
;
1206 OptionString
= *OptionalString
;
1207 OutputString
= NULL
;
1209 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1211 if (OptionString
!= NULL
) {
1212 Width
= (UINT16
) gOptionBlockWidth
;
1216 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1218 // If there is more string to process print on the next row and increment the Skip value
1220 if (StrLen (&OptionString
[Index
]) != 0) {
1221 if (SkipValue
== 0) {
1224 // Since the Number of lines for this menu entry may or may not be reflected accurately
1225 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1226 // some testing to ensure we are keeping this in-sync.
1228 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1230 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1236 FreePool (OutputString
);
1237 if (SkipValue
!= 0) {
1245 *OptionalString
= OptionString
;
1250 Check whether this Menu Option could be highlighted.
1252 This is an internal function.
1254 @param MenuOption The MenuOption to be checked.
1256 @retval TRUE This Menu Option is selectable.
1257 @retval FALSE This Menu Option could not be selected.
1262 UI_MENU_OPTION
*MenuOption
1265 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1266 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1275 Determine if the menu is the last menu that can be selected.
1277 This is an internal function.
1279 @param Direction The scroll direction. False is down. True is up.
1280 @param CurrentPos The current focus.
1282 @return FALSE -- the menu isn't the last menu that can be selected.
1283 @return TRUE -- the menu is the last menu that can be selected.
1288 IN BOOLEAN Direction
,
1289 IN LIST_ENTRY
*CurrentPos
1293 UI_MENU_OPTION
*MenuOption
;
1295 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1297 if (Temp
== &Menu
) {
1301 for (; Temp
!= &Menu
; Temp
= Direction
? Temp
->BackLink
: Temp
->ForwardLink
) {
1302 MenuOption
= MENU_OPTION_FROM_LINK (Temp
);
1303 if (IsSelectable (MenuOption
)) {
1313 Move to next selectable statement.
1315 This is an internal function.
1317 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1318 @param CurrentPosition Current position.
1320 @return The row distance from current MenuOption to next selectable MenuOption.
1324 MoveToNextStatement (
1326 IN OUT LIST_ENTRY
**CurrentPosition
1332 UI_MENU_OPTION
*NextMenuOption
;
1335 Pos
= *CurrentPosition
;
1339 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1340 if (IsSelectable (NextMenuOption
)) {
1343 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &Menu
) {
1347 Distance
+= NextMenuOption
->Skip
;
1348 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1353 // If we hit end there is still no statement can be focused,
1354 // we go backwards to find the statement can be focused.
1357 Pos
= *CurrentPosition
;
1360 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1361 if (IsSelectable (NextMenuOption
)) {
1364 if ((!GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &Menu
) {
1368 Distance
-= NextMenuOption
->Skip
;
1369 Pos
= (!GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1373 *CurrentPosition
= &NextMenuOption
->Link
;
1379 Adjust Data and Time position accordingly.
1380 Data format : [01/02/2004] [11:22:33]
1381 Line number : 0 0 1 0 0 1
1383 This is an internal function.
1385 @param DirectionUp the up or down direction. False is down. True is
1387 @param CurrentPosition Current position. On return: Point to the last
1388 Option (Year or Second) if up; Point to the first
1389 Option (Month or Hour) if down.
1391 @return Return line number to pad. It is possible that we stand on a zero-advance
1392 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1396 AdjustDateAndTimePosition (
1397 IN BOOLEAN DirectionUp
,
1398 IN OUT LIST_ENTRY
**CurrentPosition
1402 LIST_ENTRY
*NewPosition
;
1403 UI_MENU_OPTION
*MenuOption
;
1404 UINTN PadLineNumber
;
1407 NewPosition
= *CurrentPosition
;
1408 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1410 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1411 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1413 // Calculate the distance from current position to the last Date/Time MenuOption
1416 while (MenuOption
->Skip
== 0) {
1418 NewPosition
= NewPosition
->ForwardLink
;
1419 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1423 NewPosition
= *CurrentPosition
;
1426 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1427 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1428 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1429 // checking can be done.
1431 while (Count
++ < 2) {
1432 NewPosition
= NewPosition
->BackLink
;
1436 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1437 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1438 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1439 // checking can be done.
1441 while (Count
-- > 0) {
1442 NewPosition
= NewPosition
->ForwardLink
;
1446 *CurrentPosition
= NewPosition
;
1449 return PadLineNumber
;
1453 Find HII Handle in the HII database associated with given Device Path.
1455 If DevicePath is NULL, then ASSERT.
1457 @param DevicePath Device Path associated with the HII package list
1460 @retval Handle HII package list Handle associated with the Device
1462 @retval NULL Hii Package list handle is not found.
1467 DevicePathToHiiHandle (
1468 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1472 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1477 EFI_HANDLE DriverHandle
;
1478 EFI_HII_HANDLE
*HiiHandles
;
1479 EFI_HII_HANDLE HiiHandle
;
1481 ASSERT (DevicePath
!= NULL
);
1483 TmpDevicePath
= DevicePath
;
1485 // Locate Device Path Protocol handle buffer
1487 Status
= gBS
->LocateDevicePath (
1488 &gEfiDevicePathProtocolGuid
,
1492 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1497 // Retrieve all HII Handles from HII database
1499 BufferSize
= 0x1000;
1500 HiiHandles
= AllocatePool (BufferSize
);
1501 ASSERT (HiiHandles
!= NULL
);
1502 Status
= mHiiDatabase
->ListPackageLists (
1504 EFI_HII_PACKAGE_TYPE_ALL
,
1509 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1510 FreePool (HiiHandles
);
1511 HiiHandles
= AllocatePool (BufferSize
);
1512 ASSERT (HiiHandles
!= NULL
);
1514 Status
= mHiiDatabase
->ListPackageLists (
1516 EFI_HII_PACKAGE_TYPE_ALL
,
1523 if (EFI_ERROR (Status
)) {
1524 FreePool (HiiHandles
);
1529 // Search Hii Handle by Driver Handle
1532 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1533 for (Index
= 0; Index
< HandleCount
; Index
++) {
1534 Status
= mHiiDatabase
->GetPackageListHandle (
1539 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1540 HiiHandle
= HiiHandles
[Index
];
1545 FreePool (HiiHandles
);
1550 Display menu and wait for user to select one menu option, then return it.
1551 If AutoBoot is enabled, then if user doesn't select any option,
1552 after period of time, it will automatically return the first menu option.
1554 @param Selection Menu selection.
1556 @retval EFI_SUCESSS This function always return successfully for now.
1561 IN OUT UI_MENU_SELECTION
*Selection
1567 UINTN DistanceValue
;
1579 CHAR16
*OptionString
;
1580 CHAR16
*OutputString
;
1581 CHAR16
*FormattedString
;
1591 LIST_ENTRY
*TopOfScreen
;
1592 LIST_ENTRY
*SavedListEntry
;
1593 UI_MENU_OPTION
*MenuOption
;
1594 UI_MENU_OPTION
*NextMenuOption
;
1595 UI_MENU_OPTION
*SavedMenuOption
;
1596 UI_MENU_OPTION
*PreviousMenuOption
;
1597 UI_CONTROL_FLAG ControlFlag
;
1598 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1599 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1600 UI_SCREEN_OPERATION ScreenOperation
;
1601 UINT8 MinRefreshInterval
;
1604 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1605 FORM_BROWSER_STATEMENT
*Statement
;
1607 UINT8
*DevicePathBuffer
;
1610 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1612 Status
= EFI_SUCCESS
;
1613 FormattedString
= NULL
;
1614 OptionString
= NULL
;
1615 ScreenOperation
= UiNoOperation
;
1617 MinRefreshInterval
= 0;
1620 OutputString
= NULL
;
1625 MenuRefreshEntry
= gMenuRefreshHead
;
1627 NextMenuOption
= NULL
;
1628 PreviousMenuOption
= NULL
;
1629 SavedMenuOption
= NULL
;
1631 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1633 if (gClassOfVfr
== FORMSET_CLASS_FRONT_PAGE
) {
1634 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1635 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1637 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1638 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1641 Col
= LocalScreen
.LeftColumn
;
1642 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1644 Selection
->TopRow
= TopRow
;
1645 Selection
->BottomRow
= BottomRow
;
1646 Selection
->PromptCol
= Col
;
1647 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1648 Selection
->Statement
= NULL
;
1650 TopOfScreen
= Menu
.ForwardLink
;
1655 // Get user's selection
1657 NewPos
= Menu
.ForwardLink
;
1659 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1660 UpdateStatusBar (REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1662 ControlFlag
= CfInitialization
;
1663 Selection
->Action
= UI_ACTION_NONE
;
1665 switch (ControlFlag
) {
1666 case CfInitialization
:
1667 if (IsListEmpty (&Menu
)) {
1668 ControlFlag
= CfReadKey
;
1670 ControlFlag
= CfCheckSelection
;
1674 case CfCheckSelection
:
1675 if (Selection
->Action
!= UI_ACTION_NONE
) {
1676 ControlFlag
= CfExit
;
1678 ControlFlag
= CfRepaint
;
1683 ControlFlag
= CfRefreshHighLight
;
1697 LocalScreen
.LeftColumn
,
1698 LocalScreen
.RightColumn
,
1699 TopRow
- SCROLL_ARROW_HEIGHT
,
1700 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1701 FIELD_TEXT
| FIELD_BACKGROUND
1704 UiFreeRefreshList ();
1705 MinRefreshInterval
= 0;
1707 for (Link
= TopOfScreen
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
1708 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1709 MenuOption
->Row
= Row
;
1710 MenuOption
->Col
= Col
;
1711 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1713 Statement
= MenuOption
->ThisTag
;
1714 if (Statement
->InSubtitle
) {
1715 MenuOption
->Col
+= SUBTITLE_INDENT
;
1718 if (MenuOption
->GrayOut
) {
1719 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1721 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1722 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
1726 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1729 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1730 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1731 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1734 // If there is more string to process print on the next row and increment the Skip value
1736 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1742 FreePool (OutputString
);
1751 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1752 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1753 if (EFI_ERROR (Status
)) {
1755 // Repaint to clear possible error prompt pop-up
1759 ControlFlag
= CfRepaint
;
1763 if (OptionString
!= NULL
) {
1764 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1766 // If leading spaces on OptionString - remove the spaces
1768 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1769 MenuOption
->OptCol
++;
1772 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1773 OptionString
[Count
] = OptionString
[Index
];
1777 OptionString
[Count
] = CHAR_NULL
;
1781 // If Question request refresh, register the op-code
1783 if (Statement
->RefreshInterval
!= 0) {
1785 // Menu will be refreshed at minimal interval of all Questions
1786 // which have refresh request
1788 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1789 MinRefreshInterval
= Statement
->RefreshInterval
;
1792 if (gMenuRefreshHead
== NULL
) {
1793 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1794 ASSERT (MenuRefreshEntry
!= NULL
);
1795 MenuRefreshEntry
->MenuOption
= MenuOption
;
1796 MenuRefreshEntry
->Selection
= Selection
;
1797 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1798 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1799 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1800 gMenuRefreshHead
= MenuRefreshEntry
;
1803 // Advance to the last entry
1805 for (MenuRefreshEntry
= gMenuRefreshHead
;
1806 MenuRefreshEntry
->Next
!= NULL
;
1807 MenuRefreshEntry
= MenuRefreshEntry
->Next
1810 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1811 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
1812 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
1813 MenuRefreshEntry
->MenuOption
= MenuOption
;
1814 MenuRefreshEntry
->Selection
= Selection
;
1815 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1816 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1817 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
1821 Width
= (UINT16
) gOptionBlockWidth
;
1824 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1825 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1826 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1829 // If there is more string to process print on the next row and increment the Skip value
1831 if (StrLen (&OptionString
[Index
]) != 0) {
1835 // Since the Number of lines for this menu entry may or may not be reflected accurately
1836 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1837 // some testing to ensure we are keeping this in-sync.
1839 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1841 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1847 FreePool (OutputString
);
1856 FreePool (OptionString
);
1859 // If this is a text op with secondary text information
1861 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1862 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
1864 Width
= (UINT16
) gOptionBlockWidth
;
1867 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
1868 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1869 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1872 // If there is more string to process print on the next row and increment the Skip value
1874 if (StrLen (&StringPtr
[Index
]) != 0) {
1878 // Since the Number of lines for this menu entry may or may not be reflected accurately
1879 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1880 // some testing to ensure we are keeping this in-sync.
1882 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1884 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1890 FreePool (OutputString
);
1897 FreePool (StringPtr
);
1901 // Need to handle the bottom of the display
1903 if (MenuOption
->Skip
> 1) {
1904 Row
+= MenuOption
->Skip
- SkipValue
;
1907 Row
+= MenuOption
->Skip
;
1910 if (Row
> BottomRow
) {
1911 if (!ValueIsScroll (FALSE
, Link
)) {
1915 Row
= BottomRow
+ 1;
1920 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1925 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1927 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1928 TopRow
- SCROLL_ARROW_HEIGHT
,
1932 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1936 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
1938 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1939 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1943 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
1950 case CfRefreshHighLight
:
1952 // MenuOption: Last menu option that need to remove hilight
1953 // MenuOption is set to NULL in Repaint
1954 // NewPos: Current menu option that need to hilight
1956 ControlFlag
= CfUpdateHelpString
;
1959 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
1960 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
1962 SavedValue
= Repaint
;
1965 if (Selection
->QuestionId
!= 0) {
1966 NewPos
= Menu
.ForwardLink
;
1967 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1969 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &Menu
) {
1970 NewPos
= NewPos
->ForwardLink
;
1971 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1973 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
1975 // Target Question found, find its MenuOption
1979 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
1980 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1981 Index
+= SavedMenuOption
->Skip
;
1982 Link
= Link
->ForwardLink
;
1985 if (Link
!= NewPos
|| Index
> BottomRow
) {
1987 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
1990 for (Index
= TopRow
; Index
<= BottomRow
; ) {
1991 Link
= Link
->BackLink
;
1992 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1993 Index
+= SavedMenuOption
->Skip
;
1995 TopOfScreen
= Link
->ForwardLink
;
1999 ControlFlag
= CfRepaint
;
2004 // Target Question not found, highlight the default menu option
2006 NewPos
= TopOfScreen
;
2009 Selection
->QuestionId
= 0;
2012 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2013 if (MenuOption
!= NULL
) {
2015 // Remove highlight on last Menu Option
2017 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2018 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2019 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2020 if (OptionString
!= NULL
) {
2021 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2022 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2025 // If leading spaces on OptionString - remove the spaces
2027 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2030 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2031 OptionString
[Count
] = OptionString
[Index
];
2035 OptionString
[Count
] = CHAR_NULL
;
2038 Width
= (UINT16
) gOptionBlockWidth
;
2039 OriginalRow
= MenuOption
->Row
;
2041 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2042 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2043 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2046 // If there is more string to process print on the next row and increment the Skip value
2048 if (StrLen (&OptionString
[Index
]) != 0) {
2052 FreePool (OutputString
);
2055 MenuOption
->Row
= OriginalRow
;
2057 FreePool (OptionString
);
2060 if (MenuOption
->GrayOut
) {
2061 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2062 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2063 gST
->ConOut
->SetAttribute (gST
->ConOut
, SUBTITLE_TEXT
| FIELD_BACKGROUND
);
2066 OriginalRow
= MenuOption
->Row
;
2067 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2069 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2070 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2071 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2074 // If there is more string to process print on the next row and increment the Skip value
2076 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2080 FreePool (OutputString
);
2083 MenuOption
->Row
= OriginalRow
;
2084 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2090 // This is only possible if we entered this page and the first menu option is
2091 // a "non-menu" item. In that case, force it UiDown
2093 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2094 if (!IsSelectable (MenuOption
)) {
2095 ASSERT (ScreenOperation
== UiNoOperation
);
2096 ScreenOperation
= UiDown
;
2097 ControlFlag
= CfScreenOperation
;
2102 // This is the current selected statement
2104 Statement
= MenuOption
->ThisTag
;
2105 Selection
->Statement
= Statement
;
2108 // Set reverse attribute
2110 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
2111 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2114 // Assuming that we have a refresh linked-list created, lets annotate the
2115 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2116 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2118 if (gMenuRefreshHead
!= NULL
) {
2119 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2120 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT
| FIELD_BACKGROUND
;
2121 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2122 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
;
2127 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2128 if (OptionString
!= NULL
) {
2129 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2131 // If leading spaces on OptionString - remove the spaces
2133 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2136 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2137 OptionString
[Count
] = OptionString
[Index
];
2141 OptionString
[Count
] = CHAR_NULL
;
2143 Width
= (UINT16
) gOptionBlockWidth
;
2145 OriginalRow
= MenuOption
->Row
;
2147 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2148 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2149 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2152 // If there is more string to process print on the next row and increment the Skip value
2154 if (StrLen (&OptionString
[Index
]) != 0) {
2158 FreePool (OutputString
);
2161 MenuOption
->Row
= OriginalRow
;
2163 FreePool (OptionString
);
2166 OriginalRow
= MenuOption
->Row
;
2168 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2170 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2171 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2172 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2175 // If there is more string to process print on the next row and increment the Skip value
2177 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2181 FreePool (OutputString
);
2184 MenuOption
->Row
= OriginalRow
;
2189 UpdateKeyHelp (MenuOption
, FALSE
);
2192 // Clear reverse attribute
2194 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
2197 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2198 // if we didn't break halfway when process CfRefreshHighLight.
2200 Repaint
= SavedValue
;
2203 case CfUpdateHelpString
:
2204 ControlFlag
= CfPrepareToReadKey
;
2206 if (Repaint
|| NewLine
) {
2208 // Don't print anything if it is a NULL help token
2210 if (MenuOption
->ThisTag
->Help
== 0) {
2213 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2216 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2218 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2220 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2222 // Pad String with spaces to simulate a clearing of the previous line
2224 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2225 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2229 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2231 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2236 // Reset this flag every time we finish using it.
2242 case CfPrepareToReadKey
:
2243 ControlFlag
= CfReadKey
;
2244 ScreenOperation
= UiNoOperation
;
2248 ControlFlag
= CfScreenOperation
;
2251 // Wait for user's selection
2254 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2255 } while (Status
== EFI_TIMEOUT
);
2257 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2259 // IFR is updated in Callback of refresh opcode, re-parse it
2261 ControlFlag
= CfUiReset
;
2262 Selection
->Statement
= NULL
;
2266 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2268 // if we encounter error, continue to read another key in.
2270 if (EFI_ERROR (Status
)) {
2271 ControlFlag
= CfReadKey
;
2275 if (IsListEmpty (&Menu
) && Key
.UnicodeChar
!= CHAR_NULL
) {
2277 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2282 switch (Key
.UnicodeChar
) {
2283 case CHAR_CARRIAGE_RETURN
:
2284 ScreenOperation
= UiSelect
;
2289 // We will push the adjustment of these numeric values directly to the input handler
2290 // NOTE: we won't handle manual input numeric
2294 Statement
= MenuOption
->ThisTag
;
2295 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2296 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2297 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2299 if (Key
.UnicodeChar
== '+') {
2300 gDirection
= SCAN_RIGHT
;
2302 gDirection
= SCAN_LEFT
;
2304 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2305 if (EFI_ERROR (Status
)) {
2307 // Repaint to clear possible error prompt pop-up
2312 if (OptionString
!= NULL
) {
2313 FreePool (OptionString
);
2319 ScreenOperation
= UiUp
;
2324 ScreenOperation
= UiDown
;
2328 if (gClassOfVfr
!= FORMSET_CLASS_FRONT_PAGE
) {
2329 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2330 ScreenOperation
= UiSelect
;
2336 if (((Key
.ScanCode
== SCAN_F1
) && ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
)) ||
2337 ((Key
.ScanCode
== SCAN_F2
) && ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
)) ||
2338 ((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2339 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2342 // If the function key has been disabled, just ignore the key.
2345 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2346 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2347 if (Key
.ScanCode
== SCAN_F9
) {
2349 // Reset to standard default
2351 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2353 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2362 case CfScreenOperation
:
2363 if (ScreenOperation
!= UiPrevious
&& ScreenOperation
!= UiReset
) {
2365 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
2366 // ignore the selection and go back to reading keys.
2368 if (IsListEmpty (&Menu
)) {
2369 ControlFlag
= CfReadKey
;
2373 // if there is nothing logical to place a cursor on, just move on to wait for a key.
2375 for (Link
= Menu
.ForwardLink
; Link
!= &Menu
; Link
= Link
->ForwardLink
) {
2376 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2377 if (IsSelectable (NextMenuOption
)) {
2382 if (Link
== &Menu
) {
2383 ControlFlag
= CfPrepareToReadKey
;
2386 } else if (ScreenOperation
== UiReset
) {
2388 // Press ESC to exit FormSet
2390 Selection
->Action
= UI_ACTION_EXIT
;
2391 Selection
->Statement
= NULL
;
2395 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2398 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2399 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2406 ControlFlag
= CfCheckSelection
;
2408 if (IsListEmpty (&gMenuList
)) {
2409 Selection
->Action
= UI_ACTION_NONE
;
2410 if (IsListEmpty (&Menu
)) {
2411 ControlFlag
= CfReadKey
;
2417 // Remove the Cached page entry
2419 UiRemoveMenuListEntry (Selection
);
2421 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2422 Selection
->Statement
= NULL
;
2426 ControlFlag
= CfCheckSelection
;
2428 Statement
= MenuOption
->ThisTag
;
2429 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) ||
2430 (Statement
->Operand
== EFI_IFR_DATE_OP
) ||
2431 (Statement
->Operand
== EFI_IFR_TIME_OP
) ||
2432 (Statement
->Operand
== EFI_IFR_NUMERIC_OP
&& Statement
->Step
!= 0)) {
2437 // Keep highlight on current MenuOption
2439 Selection
->QuestionId
= Statement
->QuestionId
;
2441 switch (Statement
->Operand
) {
2442 case EFI_IFR_REF_OP
:
2443 if (Statement
->RefDevicePath
!= 0) {
2445 // Goto another Hii Package list
2447 ControlFlag
= CfUiReset
;
2448 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2450 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2451 if (StringPtr
== NULL
) {
2453 // No device path string not found, exit
2455 Selection
->Action
= UI_ACTION_EXIT
;
2456 Selection
->Statement
= NULL
;
2459 BufferSize
= StrLen (StringPtr
) / 2;
2460 DevicePath
= AllocatePool (BufferSize
);
2463 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2465 DevicePathBuffer
= (UINT8
*) DevicePath
;
2466 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2467 TemStr
[0] = StringPtr
[Index
];
2468 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2469 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2471 // Invalid Hex Char as the tail.
2475 if ((Index
& 1) == 0) {
2476 DevicePathBuffer
[Index
/2] = DigitUint8
;
2478 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2482 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2483 if (Selection
->Handle
== NULL
) {
2485 // If target Hii Handle not found, exit
2487 Selection
->Action
= UI_ACTION_EXIT
;
2488 Selection
->Statement
= NULL
;
2492 FreePool (StringPtr
);
2493 FreePool (DevicePath
);
2495 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2496 Selection
->FormId
= Statement
->RefFormId
;
2497 Selection
->QuestionId
= Statement
->RefQuestionId
;
2498 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2500 // Goto another Formset, check for uncommitted data
2502 ControlFlag
= CfUiReset
;
2503 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2505 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2506 Selection
->FormId
= Statement
->RefFormId
;
2507 Selection
->QuestionId
= Statement
->RefQuestionId
;
2508 } else if (Statement
->RefFormId
!= 0) {
2510 // Goto another form inside this formset,
2512 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2515 // Link current form so that we can always go back when someone hits the UiPrevious
2517 UiAddMenuListEntry (Selection
);
2519 Selection
->FormId
= Statement
->RefFormId
;
2520 Selection
->QuestionId
= Statement
->RefQuestionId
;
2521 } else if (Statement
->RefQuestionId
!= 0) {
2523 // Goto another Question
2525 Selection
->QuestionId
= Statement
->RefQuestionId
;
2527 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2528 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2537 case EFI_IFR_ACTION_OP
:
2539 // Process the Config string <ConfigResp>
2541 Status
= ProcessQuestionConfig (Selection
, Statement
);
2543 if (EFI_ERROR (Status
)) {
2548 // The action button may change some Question value, so refresh the form
2550 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2553 case EFI_IFR_RESET_BUTTON_OP
:
2555 // Reset Question to default value specified by DefaultId
2557 ControlFlag
= CfUiDefault
;
2558 DefaultId
= Statement
->DefaultId
;
2563 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2565 UpdateKeyHelp (MenuOption
, TRUE
);
2566 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2568 if (EFI_ERROR (Status
)) {
2571 UpdateKeyHelp (MenuOption
, FALSE
);
2573 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2576 if (OptionString
!= NULL
) {
2577 FreePool (OptionString
);
2585 // We are going to leave current FormSet, so check uncommited data in this FormSet
2587 ControlFlag
= CfCheckSelection
;
2589 if (gClassOfVfr
== FORMSET_CLASS_FRONT_PAGE
) {
2591 // There is no parent menu for FrontPage
2593 Selection
->Action
= UI_ACTION_NONE
;
2594 Selection
->Statement
= MenuOption
->ThisTag
;
2599 // If NV flag is up, prompt user
2601 if (gNvUpdateRequired
) {
2602 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2604 YesResponse
= gYesResponse
[0];
2605 NoResponse
= gNoResponse
[0];
2608 CreateDialog (3, TRUE
, 0, NULL
, &Key
, gEmptyString
, gAreYouSure
, gEmptyString
);
2611 (Key
.ScanCode
!= SCAN_ESC
) &&
2612 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (NoResponse
| UPPER_LOWER_CASE_OFFSET
)) &&
2613 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (YesResponse
| UPPER_LOWER_CASE_OFFSET
))
2617 // If the user hits the YesResponse key
2619 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (YesResponse
| UPPER_LOWER_CASE_OFFSET
)) {
2624 Selection
->Action
= UI_ACTION_NONE
;
2629 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2630 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
2633 gST
->ConOut
->ClearScreen (gST
->ConOut
);
2637 ControlFlag
= CfCheckSelection
;
2638 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2639 if (MenuOption
->Sequence
!= 0) {
2641 // In the middle or tail of the Date/Time op-code set, go left.
2643 NewPos
= NewPos
->BackLink
;
2649 ControlFlag
= CfCheckSelection
;
2650 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2651 if (MenuOption
->Sequence
!= 2) {
2653 // In the middle or tail of the Date/Time op-code set, go left.
2655 NewPos
= NewPos
->ForwardLink
;
2661 ControlFlag
= CfCheckSelection
;
2663 SavedListEntry
= TopOfScreen
;
2665 if (NewPos
->BackLink
!= &Menu
) {
2668 // Adjust Date/Time position before we advance forward.
2670 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2673 // Caution that we have already rewind to the top, don't go backward in this situation.
2675 if (NewPos
->BackLink
!= &Menu
) {
2676 NewPos
= NewPos
->BackLink
;
2679 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2680 DistanceValue
= PreviousMenuOption
->Skip
;
2683 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
2684 // to be one that back to the previous set of op-codes, we need to advance to the sencond
2685 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2686 // checking can be done.
2688 DistanceValue
+= AdjustDateAndTimePosition (TRUE
, &NewPos
);
2691 // Check the previous menu entry to see if it was a zero-length advance. If it was,
2692 // don't worry about a redraw.
2694 if ((INTN
) MenuOption
->Row
- (INTN
) DistanceValue
< (INTN
) TopRow
) {
2696 TopOfScreen
= NewPos
;
2699 Difference
= MoveToNextStatement (TRUE
, &NewPos
);
2700 if ((INTN
) MenuOption
->Row
- (INTN
) DistanceValue
< (INTN
) TopRow
) {
2701 if (Difference
> 0) {
2703 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2705 TopOfScreen
= NewPos
;
2709 if (Difference
< 0) {
2711 // We want to goto previous MenuOption, but finally we go down.
2712 // it means that we hit the begining MenuOption that can be focused
2713 // so we simply scroll to the top
2715 if (SavedListEntry
!= Menu
.ForwardLink
) {
2716 TopOfScreen
= Menu
.ForwardLink
;
2722 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2724 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2726 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2728 SavedMenuOption
= MenuOption
;
2729 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2730 if (!IsSelectable (MenuOption
)) {
2732 // If we are at the end of the list and sitting on a text op, we need to more forward
2734 ScreenOperation
= UiDown
;
2735 ControlFlag
= CfScreenOperation
;
2739 MenuOption
= SavedMenuOption
;
2744 ControlFlag
= CfCheckSelection
;
2746 if (NewPos
->BackLink
== &Menu
) {
2755 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2757 while ((Index
>= TopRow
) && (Link
->BackLink
!= &Menu
)) {
2758 Index
= Index
- PreviousMenuOption
->Skip
;
2759 Link
= Link
->BackLink
;
2760 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2764 Difference
= MoveToNextStatement (TRUE
, &Link
);
2765 if (Difference
> 0) {
2767 // The focus MenuOption is above the TopOfScreen
2770 } else if (Difference
< 0) {
2772 // This happens when there is no MenuOption can be focused from
2773 // Current MenuOption to the first MenuOption
2775 TopOfScreen
= Menu
.ForwardLink
;
2777 Index
+= Difference
;
2778 if (Index
< TopRow
) {
2782 if (NewPos
== Link
) {
2790 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2791 // Don't do this when we are already in the first page.
2793 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2794 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2798 ControlFlag
= CfCheckSelection
;
2800 if (NewPos
->ForwardLink
== &Menu
) {
2809 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2811 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &Menu
)) {
2812 Index
= Index
+ NextMenuOption
->Skip
;
2813 Link
= Link
->ForwardLink
;
2814 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2817 Index
+= MoveToNextStatement (FALSE
, &Link
);
2818 if (Index
> BottomRow
) {
2820 // There are more MenuOption needing scrolling
2825 if (NewPos
== Link
&& Index
<= BottomRow
) {
2827 // Finally we know that NewPos is the last MenuOption can be focused.
2836 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2837 // Don't do this when we are already in the last page.
2839 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2840 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2844 ControlFlag
= CfCheckSelection
;
2846 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2847 // to be one that progresses to the next set of op-codes, we need to advance to the last
2848 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2849 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2850 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2851 // the Date/Time op-code.
2853 SavedListEntry
= NewPos
;
2854 DistanceValue
= AdjustDateAndTimePosition (FALSE
, &NewPos
);
2856 if (NewPos
->ForwardLink
!= &Menu
) {
2857 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2859 NewPos
= NewPos
->ForwardLink
;
2860 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2862 DistanceValue
+= NextMenuOption
->Skip
;
2863 DistanceValue
+= MoveToNextStatement (FALSE
, &NewPos
);
2865 // An option might be multi-line, so we need to reflect that data in the overall skip value
2867 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, SkipValue
);
2869 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
2870 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
2871 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
2872 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2878 // If we are going to scroll, update TopOfScreen
2880 if (Temp
> BottomRow
) {
2883 // Is the current top of screen a zero-advance op-code?
2884 // If so, keep moving forward till we hit a >0 advance op-code
2886 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2889 // If bottom op-code is more than one line or top op-code is more than one line
2891 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
2893 // Is the bottom op-code greater than or equal in size to the top op-code?
2895 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
2897 // Skip the top op-code
2899 TopOfScreen
= TopOfScreen
->ForwardLink
;
2900 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
2902 OldSkipValue
= Difference
;
2904 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2907 // If we have a remainder, skip that many more op-codes until we drain the remainder
2910 Difference
>= (INTN
) SavedMenuOption
->Skip
;
2911 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
2914 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2916 TopOfScreen
= TopOfScreen
->ForwardLink
;
2917 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2918 if (Difference
< (INTN
) SavedMenuOption
->Skip
) {
2919 Difference
= SavedMenuOption
->Skip
- Difference
- 1;
2922 if (Difference
== (INTN
) SavedMenuOption
->Skip
) {
2923 TopOfScreen
= TopOfScreen
->ForwardLink
;
2924 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2925 Difference
= SavedMenuOption
->Skip
- Difference
;
2931 // Since we will act on this op-code in the next routine, and increment the
2932 // SkipValue, set the skips to one less than what is required.
2934 SkipValue
= Difference
- 1;
2938 // Since we will act on this op-code in the next routine, and increment the
2939 // SkipValue, set the skips to one less than what is required.
2941 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
2944 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2945 TopOfScreen
= TopOfScreen
->ForwardLink
;
2948 SkipValue
= OldSkipValue
;
2952 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2953 // Let's set a skip flag to smoothly scroll the top of the screen.
2955 if (SavedMenuOption
->Skip
> 1) {
2956 if (SavedMenuOption
== NextMenuOption
) {
2963 TopOfScreen
= TopOfScreen
->ForwardLink
;
2965 } while (SavedMenuOption
->Skip
== 0);
2968 OldSkipValue
= SkipValue
;
2971 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2973 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2976 SavedMenuOption
= MenuOption
;
2977 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2978 if (!IsSelectable (MenuOption
)) {
2980 // If we are at the end of the list and sitting on a text op, we need to more forward
2982 ScreenOperation
= UiUp
;
2983 ControlFlag
= CfScreenOperation
;
2987 MenuOption
= SavedMenuOption
;
2989 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2991 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2996 ControlFlag
= CfCheckSelection
;
3001 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
);
3003 if (!EFI_ERROR (Status
)) {
3004 UpdateStatusBar (INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3005 UpdateStatusBar (NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3008 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3009 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3017 ControlFlag
= CfCheckSelection
;
3019 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3021 if (!EFI_ERROR (Status
)) {
3022 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3023 Selection
->Statement
= NULL
;
3026 // Show NV update flag on status bar
3028 gNvUpdateRequired
= TRUE
;
3032 case CfUiNoOperation
:
3033 ControlFlag
= CfCheckSelection
;
3037 UiFreeRefreshList ();
3039 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3040 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3041 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3042 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");