2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2013, 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.
15 #include "FormDisplay.h"
18 // Search table for UiDisplayMenu()
20 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
51 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
53 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
96 EFI_GUID gDisplayEngineGuid
= {
97 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
101 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
102 EFI_SCREEN_DESCRIPTOR gOldStatementDimensions
= {0};
103 BOOLEAN mStatementLayoutIsChanged
= TRUE
;
104 USER_INPUT
*gUserInput
;
105 FORM_DISPLAY_ENGINE_FORM
*gFormData
;
106 EFI_HII_HANDLE gHiiHandle
;
108 LIST_ENTRY gMenuOption
;
109 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo
= {0};
112 // Browser Global Strings
114 CHAR16
*gFormNotFound
;
116 CHAR16
*gBrwoserError
;
118 CHAR16
*gPromptForData
;
119 CHAR16
*gPromptForPassword
;
120 CHAR16
*gPromptForNewPassword
;
121 CHAR16
*gConfirmPassword
;
122 CHAR16
*gConfirmError
;
123 CHAR16
*gPassowordInvalid
;
125 CHAR16
*gEmptyString
;
127 CHAR16
*gOptionMismatch
;
128 CHAR16
*gFormSuppress
;
129 CHAR16
*gProtocolNotFound
;
131 CHAR16 gPromptBlockWidth
;
132 CHAR16 gOptionBlockWidth
;
133 CHAR16 gHelpBlockWidth
;
134 CHAR16
*mUnknownString
;
136 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
137 FORM_DISPLAY_DRIVER_SIGNATURE
,
148 Get the string based on the StringId and HII Package List Handle.
150 @param Token The String's ID.
151 @param HiiHandle The package list in the HII database to search for
152 the specified string.
154 @return The output string.
159 IN EFI_STRING_ID Token
,
160 IN EFI_HII_HANDLE HiiHandle
165 String
= HiiGetString (HiiHandle
, Token
, NULL
);
166 if (String
== NULL
) {
167 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
168 ASSERT (String
!= NULL
);
171 return (CHAR16
*) String
;
176 Initialize the HII String Token to the correct values.
180 InitializeDisplayStrings (
184 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
185 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
186 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
187 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
188 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
189 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
190 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
191 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
192 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
193 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
194 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
195 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
196 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
197 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
198 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
199 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
200 gBrwoserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
204 Free up the resource allocated for all strings required
213 FreePool (mUnknownString
);
214 FreePool (gEmptyString
);
215 FreePool (gSaveFailed
);
216 FreePool (gPromptForData
);
217 FreePool (gPromptForPassword
);
218 FreePool (gPromptForNewPassword
);
219 FreePool (gConfirmPassword
);
220 FreePool (gConfirmError
);
221 FreePool (gPassowordInvalid
);
222 FreePool (gPressEnter
);
223 FreePool (gMiniString
);
224 FreePool (gOptionMismatch
);
225 FreePool (gFormSuppress
);
226 FreePool (gProtocolNotFound
);
227 FreePool (gBrwoserError
);
228 FreePool (gNoSubmitIf
);
229 FreePool (gFormNotFound
);
233 Get prompt string id from the opcode data buffer.
235 @param OpCode The input opcode buffer.
237 @return The prompt string id.
242 IN EFI_IFR_OP_HEADER
*OpCode
245 EFI_IFR_STATEMENT_HEADER
*Header
;
247 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
251 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
253 return Header
->Prompt
;
257 Get the supported width for a particular op-code
259 @param Statement The curent statement.
261 @return Returns the number of CHAR16 characters that is support.
266 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
272 EFI_IFR_TEXT
*TestOp
;
277 // See if the second text parameter is really NULL
279 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
280 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
281 if (TestOp
->TextTwo
!= 0) {
282 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
283 Size
= StrLen (String
);
288 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
289 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
290 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
291 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
292 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
294 // Allow a wide display if text op-code and no secondary text op-code
296 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
298 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
300 Width
= (UINT16
) gPromptBlockWidth
;
303 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
307 Will copy LineWidth amount of a string in the OutputString buffer and return the
308 number of CHAR16 characters that were copied into the OutputString buffer.
309 The output string format is:
310 Glyph Info + String info + '\0'.
312 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
314 @param InputString String description for this option.
315 @param LineWidth Width of the desired string to extract in CHAR16
317 @param GlyphWidth The glyph width of the begin of the char in the string.
318 @param Index Where in InputString to start the copy process
319 @param OutputString Buffer to copy the string into
321 @return Returns the number of CHAR16 characters that were copied into the OutputString
322 buffer, include extra glyph info and '\0' info.
327 IN CHAR16
*InputString
,
329 IN OUT UINT16
*GlyphWidth
,
331 OUT CHAR16
**OutputString
336 UINT16 OriginalGlyphWidth
;
338 UINT16 LastSpaceOffset
;
339 UINT16 LastGlyphWidth
;
341 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
345 if (LineWidth
== 0 || *GlyphWidth
== 0) {
350 // Save original glyph width.
352 OriginalGlyphWidth
= *GlyphWidth
;
353 LastGlyphWidth
= OriginalGlyphWidth
;
358 // 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.
359 // To avoid displaying this empty line in screen, just skip the two CHARs here.
361 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
366 // Fast-forward the string and see if there is a carriage-return in the string
368 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
369 switch (InputString
[*Index
+ StrOffset
]) {
378 case CHAR_CARRIAGE_RETURN
:
385 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
388 // Record the last space info in this line. Will be used in rewind.
390 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
391 LastSpaceOffset
= StrOffset
;
392 LastGlyphWidth
= *GlyphWidth
;
403 // Rewind the string from the maximum size until we see a space to break the line
405 if (GlyphOffset
> LineWidth
) {
407 // Rewind the string to last space char in this line.
409 if (LastSpaceOffset
!= 0) {
410 StrOffset
= LastSpaceOffset
;
411 *GlyphWidth
= LastGlyphWidth
;
414 // Roll back to last char in the line width.
421 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
423 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
428 // Need extra glyph info and '\0' info, so +2.
430 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
431 if (*OutputString
== NULL
) {
436 // Save the glyph info at the begin of the string, will used by Print function.
438 if (OriginalGlyphWidth
== 1) {
439 *(*OutputString
) = NARROW_CHAR
;
441 *(*OutputString
) = WIDE_CHAR
;
444 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
446 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
448 // Skip the space info at the begin of next line.
450 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
451 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
453 // Skip the /n or /n/r info.
455 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
456 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
458 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
460 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
462 // Skip the /r or /r/n info.
464 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
465 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
467 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
470 *Index
= (UINT16
) (*Index
+ StrOffset
);
474 // Include extra glyph info and '\0' info, so +2.
476 return StrOffset
+ 2;
480 Add one menu option by specified description and context.
482 @param Statement Statement of this Menu Option.
483 @param MenuItemCount The index for this Option in the Menu.
484 @param NestIn Whether this statement is nest in another statement.
489 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
490 IN UINT16
*MenuItemCount
,
494 UI_MENU_OPTION
*MenuOption
;
498 UINT16 NumberOfLines
;
502 CHAR16
*OutputString
;
503 EFI_STRING_ID PromptId
;
511 PromptId
= GetPrompt (Statement
->OpCode
);
512 ASSERT (PromptId
!= 0);
514 String
= GetToken (PromptId
, gFormData
->HiiHandle
);
515 ASSERT (String
!= NULL
);
517 Width
= GetWidth (Statement
);
518 for (; GetLineByWidth (String
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
520 // If there is more string to process print on the next row and increment the Skip value
522 if (StrLen (&String
[ArrayEntry
]) != 0) {
525 FreePool (OutputString
);
528 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
530 // Add three MenuOptions for Date/Time
531 // Data format : [01/02/2004] [11:22:33]
532 // Line number : 0 0 1 0 0 1
538 for (Index
= 0; Index
< Count
; Index
++) {
539 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
542 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
543 MenuOption
->Description
= String
;
544 MenuOption
->Handle
= gFormData
->HiiHandle
;
545 MenuOption
->ThisTag
= Statement
;
546 MenuOption
->NestInStatement
= NestIn
;
547 MenuOption
->EntryNumber
= *MenuItemCount
;
551 // Override LineNumber for the MenuOption in Date/Time sequence
553 MenuOption
->Skip
= 1;
555 MenuOption
->Skip
= NumberOfLines
;
557 MenuOption
->Sequence
= Index
;
559 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
560 MenuOption
->GrayOut
= TRUE
;
562 MenuOption
->GrayOut
= FALSE
;
565 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
566 MenuOption
->GrayOut
= TRUE
;
570 // If the form or the question has the lock attribute, deal same as grayout.
572 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
573 MenuOption
->GrayOut
= TRUE
;
576 switch (Statement
->OpCode
->OpCode
) {
577 case EFI_IFR_ORDERED_LIST_OP
:
578 case EFI_IFR_ONE_OF_OP
:
579 case EFI_IFR_NUMERIC_OP
:
580 case EFI_IFR_TIME_OP
:
581 case EFI_IFR_DATE_OP
:
582 case EFI_IFR_CHECKBOX_OP
:
583 case EFI_IFR_PASSWORD_OP
:
584 case EFI_IFR_STRING_OP
:
586 // User could change the value of these items
588 MenuOption
->IsQuestion
= TRUE
;
590 case EFI_IFR_TEXT_OP
:
591 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
593 // Initializing GrayOut option as TRUE for Text setup options
594 // so that those options will be Gray in colour and un selectable.
596 MenuOption
->GrayOut
= TRUE
;
600 MenuOption
->IsQuestion
= FALSE
;
604 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
605 MenuOption
->ReadOnly
= TRUE
;
606 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
607 MenuOption
->GrayOut
= TRUE
;
611 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
618 Create the menu list base on the form data info.
622 ConvertStatementToMenu (
626 UINT16 MenuItemCount
;
628 LIST_ENTRY
*NestLink
;
629 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
630 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
633 InitializeListHead (&gMenuOption
);
635 Link
= GetFirstNode (&gFormData
->StatementListHead
);
636 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
637 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
638 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
641 // Skip the opcode not recognized by Display core.
643 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
647 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
650 // Check the statement nest in this host statement.
652 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
653 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
654 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
655 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
657 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
663 Count the storage space of a Unicode string.
665 This function handles the Unicode string with NARROW_CHAR
666 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
667 does not count in the resultant output. If a WIDE_CHAR is
668 hit, then 2 Unicode character will consume an output storage
669 space with size of CHAR16 till a NARROW_CHAR is hit.
671 If String is NULL, then ASSERT ().
673 @param String The input string to be counted.
675 @return Storage space for the input string.
685 UINTN IncrementValue
;
687 ASSERT (String
!= NULL
);
688 if (String
== NULL
) {
698 // Advance to the null-terminator or to the first width directive
701 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
702 Index
++, Count
= Count
+ IncrementValue
707 // We hit the null-terminator, we now have a count
709 if (String
[Index
] == 0) {
713 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
714 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
716 if (String
[Index
] == NARROW_CHAR
) {
718 // Skip to the next character
724 // Skip to the next character
729 } while (String
[Index
] != 0);
732 // Increment by one to include the null-terminator in the size
736 return Count
* sizeof (CHAR16
);
740 Base on the input option string to update the skip value for a menu option.
742 @param MenuOption The MenuOption to be checked.
743 @param OptionString The input option string.
747 UpdateSkipInfoForMenu (
748 IN UI_MENU_OPTION
*MenuOption
,
749 IN CHAR16
*OptionString
755 CHAR16
*OutputString
;
758 Width
= (UINT16
) gOptionBlockWidth
;
762 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
763 if (StrLen (&OptionString
[Index
]) != 0) {
767 FreePool (OutputString
);
770 if ((Row
> MenuOption
->Skip
) &&
771 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
772 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
773 MenuOption
->Skip
= Row
;
778 Update display lines for a Menu Option.
780 @param MenuOption The MenuOption to be checked.
784 UpdateOptionSkipLines (
785 IN UI_MENU_OPTION
*MenuOption
788 CHAR16
*OptionString
;
792 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
793 if (OptionString
!= NULL
) {
794 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
796 FreePool (OptionString
);
799 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
800 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
802 if (OptionString
!= NULL
) {
803 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
805 FreePool (OptionString
);
811 Check whether this Menu Option could be highlighted.
813 This is an internal function.
815 @param MenuOption The MenuOption to be checked.
817 @retval TRUE This Menu Option is selectable.
818 @retval FALSE This Menu Option could not be selected.
823 UI_MENU_OPTION
*MenuOption
826 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
827 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
835 Move to next selectable statement.
837 This is an internal function.
839 @param GoUp The navigation direction. TRUE: up, FALSE: down.
840 @param CurrentPosition Current position.
841 @param GapToTop Gap position to top or bottom.
843 @return The row distance from current MenuOption to next selectable MenuOption.
845 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
846 @retval Value Find the selectable menu, maybe the truly selectable, maybe the l
847 last menu showing at current form.
851 MoveToNextStatement (
853 IN OUT LIST_ENTRY
**CurrentPosition
,
859 UI_MENU_OPTION
*NextMenuOption
;
860 UI_MENU_OPTION
*PreMenuOption
;
863 Pos
= *CurrentPosition
;
864 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
867 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
869 // NextMenuOption->Row == 0 means this menu has not calculate
870 // the NextMenuOption->Skip value yet, just calculate here.
872 if (NextMenuOption
->Row
== 0) {
873 UpdateOptionSkipLines (NextMenuOption
);
876 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
878 // In this case, still can't find the selectable menu,
879 // return the last one in the showing form.
881 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
882 NextMenuOption
= PreMenuOption
;
887 // Current Position doesn't need to be caculated when go up.
888 // Caculate distanct at first when go up
890 Distance
+= NextMenuOption
->Skip
;
893 if (IsSelectable (NextMenuOption
)) {
898 // Arrive at begin of the menu list.
900 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
907 // In this case, still can't find the selectable menu,
908 // return the last one in the showing form.
910 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
911 NextMenuOption
= PreMenuOption
;
915 Distance
+= NextMenuOption
->Skip
;
918 PreMenuOption
= NextMenuOption
;
919 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
922 *CurrentPosition
= &NextMenuOption
->Link
;
928 Process option string for date/time opcode.
930 @param MenuOption Menu option point to date/time.
931 @param OptionString Option string input for process.
932 @param AddOptCol Whether need to update MenuOption->OptCol.
936 ProcessStringForDateTime (
937 UI_MENU_OPTION
*MenuOption
,
938 CHAR16
*OptionString
,
944 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
948 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
950 Statement
= MenuOption
->ThisTag
;
953 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
954 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
955 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
956 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
960 // If leading spaces on OptionString - remove the spaces
962 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
964 // Base on the blockspace to get the option column info.
967 MenuOption
->OptCol
++;
971 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
972 OptionString
[Count
] = OptionString
[Index
];
975 OptionString
[Count
] = CHAR_NULL
;
978 // Enable to suppress field in the opcode base on the flag.
980 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
982 // OptionString format is: <**: **: ****>
986 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
988 // At this point, only "<**:" in the optionstring.
989 // Clean the day's ** field, after clean, the format is "< :"
991 SetUnicodeMem (&OptionString
[1], 2, L
' ');
992 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
994 // At this point, only "**:" in the optionstring.
995 // Clean the month's "**" field, after clean, the format is " :"
997 SetUnicodeMem (&OptionString
[0], 2, L
' ');
998 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1000 // At this point, only "****>" in the optionstring.
1001 // Clean the year's "****" field, after clean, the format is " >"
1003 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1005 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1007 // OptionString format is: <**: **: **>
1008 // |hour|minute|second|
1011 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1013 // At this point, only "<**:" in the optionstring.
1014 // Clean the hour's ** field, after clean, the format is "< :"
1016 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1017 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1019 // At this point, only "**:" in the optionstring.
1020 // Clean the minute's "**" field, after clean, the format is " :"
1022 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1023 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1025 // At this point, only "**>" in the optionstring.
1026 // Clean the second's "**" field, after clean, the format is " >"
1028 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1035 Adjust Data and Time position accordingly.
1036 Data format : [01/02/2004] [11:22:33]
1037 Line number : 0 0 1 0 0 1
1039 This is an internal function.
1041 @param DirectionUp the up or down direction. False is down. True is
1043 @param CurrentPosition Current position. On return: Point to the last
1044 Option (Year or Second) if up; Point to the first
1045 Option (Month or Hour) if down.
1047 @return Return line number to pad. It is possible that we stand on a zero-advance
1048 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1052 AdjustDateAndTimePosition (
1053 IN BOOLEAN DirectionUp
,
1054 IN OUT LIST_ENTRY
**CurrentPosition
1058 LIST_ENTRY
*NewPosition
;
1059 UI_MENU_OPTION
*MenuOption
;
1060 UINTN PadLineNumber
;
1063 NewPosition
= *CurrentPosition
;
1064 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1066 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1067 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1069 // Calculate the distance from current position to the last Date/Time MenuOption
1072 while (MenuOption
->Skip
== 0) {
1074 NewPosition
= NewPosition
->ForwardLink
;
1075 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1079 NewPosition
= *CurrentPosition
;
1082 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1083 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1084 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1085 // checking can be done.
1087 while (Count
++ < 2) {
1088 NewPosition
= NewPosition
->BackLink
;
1092 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1093 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1094 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1095 // checking can be done.
1097 while (Count
-- > 0) {
1098 NewPosition
= NewPosition
->ForwardLink
;
1102 *CurrentPosition
= NewPosition
;
1105 return PadLineNumber
;
1109 Get step info from numeric opcode.
1111 @param[in] OpCode The input numeric op code.
1113 @return step info for this opcode.
1117 IN EFI_IFR_OP_HEADER
*OpCode
1120 EFI_IFR_NUMERIC
*NumericOp
;
1123 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1125 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1126 case EFI_IFR_NUMERIC_SIZE_1
:
1127 Step
= NumericOp
->data
.u8
.Step
;
1130 case EFI_IFR_NUMERIC_SIZE_2
:
1131 Step
= NumericOp
->data
.u16
.Step
;
1134 case EFI_IFR_NUMERIC_SIZE_4
:
1135 Step
= NumericOp
->data
.u32
.Step
;
1138 case EFI_IFR_NUMERIC_SIZE_8
:
1139 Step
= NumericOp
->data
.u64
.Step
;
1151 Find the registered HotKey based on KeyData.
1153 @param[in] KeyData A pointer to a buffer that describes the keystroke
1154 information for the hot key.
1156 @return The registered HotKey context. If no found, NULL will return.
1159 GetHotKeyFromRegisterList (
1160 IN EFI_INPUT_KEY
*KeyData
1164 BROWSER_HOT_KEY
*HotKey
;
1166 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1167 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1168 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1170 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1174 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1182 Determine if the menu is the last menu that can be selected.
1184 This is an internal function.
1186 @param Direction The scroll direction. False is down. True is up.
1187 @param CurrentPos The current focus.
1189 @return FALSE -- the menu isn't the last menu that can be selected.
1190 @return TRUE -- the menu is the last menu that can be selected.
1195 IN BOOLEAN Direction
,
1196 IN LIST_ENTRY
*CurrentPos
1201 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1203 if (Temp
== &gMenuOption
) {
1211 Wait for a given event to fire, or for an optional timeout to expire.
1213 @param Event The event to wait for
1215 @retval UI_EVENT_TYPE The type of the event which is trigged.
1227 EFI_EVENT TimerEvent
;
1228 EFI_EVENT WaitList
[3];
1229 UI_EVENT_TYPE EventType
;
1232 Timeout
= FormExitTimeout(gFormData
);
1235 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1238 // Set the timer event
1247 WaitList
[0] = Event
;
1249 if (gFormData
->FormRefreshEvent
!= NULL
) {
1250 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1255 WaitList
[EventNum
] = TimerEvent
;
1259 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1260 ASSERT_EFI_ERROR (Status
);
1264 EventType
= UIEventKey
;
1268 if (gFormData
->FormRefreshEvent
!= NULL
) {
1269 EventType
= UIEventDriver
;
1271 ASSERT (Timeout
!= 0 && EventNum
== 2);
1272 EventType
= UIEventTimeOut
;
1277 ASSERT (Index
== 2 && EventNum
== 3);
1278 EventType
= UIEventTimeOut
;
1283 gBS
->CloseEvent (TimerEvent
);
1290 Get question id info from the input opcode header.
1292 @param OpCode The input opcode header pointer.
1294 @retval The question id for this opcode.
1299 IN EFI_IFR_OP_HEADER
*OpCode
1302 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1304 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1308 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1310 return QuestionHeader
->QuestionId
;
1314 Find the first menu which will be show at the top.
1316 @param FormData The data info for this form.
1317 @param TopOfScreen The link_entry pointer to top menu.
1318 @param HighlightMenu The menu which will be highlight.
1319 @param SkipValue The skip value for the top menu.
1324 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1325 OUT LIST_ENTRY
**TopOfScreen
,
1326 OUT LIST_ENTRY
**HighlightMenu
,
1335 UI_MENU_OPTION
*SavedMenuOption
;
1338 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1339 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1342 // If not has input highlight statement, just return the first one in this form.
1344 if (FormData
->HighLightedStatement
== NULL
) {
1345 *TopOfScreen
= gMenuOption
.ForwardLink
;
1346 *HighlightMenu
= gMenuOption
.ForwardLink
;
1347 if (!IsListEmpty (&gMenuOption
)) {
1348 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
);
1355 // Now base on the input highlight menu to find the top menu in this page.
1356 // Will base on the highlight menu show at the bottom to find the top menu.
1358 NewPos
= gMenuOption
.ForwardLink
;
1359 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1361 while ((SavedMenuOption
->ThisTag
!= FormData
->HighLightedStatement
) ||
1362 (SavedMenuOption
->Sequence
!= gSequence
)) {
1363 NewPos
= NewPos
->ForwardLink
;
1364 if (NewPos
== &gMenuOption
) {
1366 // Not Found it, break
1370 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1372 ASSERT (SavedMenuOption
->ThisTag
== FormData
->HighLightedStatement
);
1374 *HighlightMenu
= NewPos
;
1376 AdjustDateAndTimePosition(FALSE
, &NewPos
);
1377 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1378 UpdateOptionSkipLines (SavedMenuOption
);
1381 // If highlight opcode is date/time, keep the highlight row info not change.
1383 if ((SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) &&
1384 (gHighligthMenuInfo
.QuestionId
!= 0) &&
1385 (gHighligthMenuInfo
.QuestionId
== GetQuestionIdInfo(SavedMenuOption
->ThisTag
->OpCode
))) {
1387 // Still show the highlight menu before exit from display engine.
1389 EndRow
= gHighligthMenuInfo
.DisplayRow
+ SavedMenuOption
->Skip
;
1395 // Base on the selected menu will show at the bottome of next page,
1396 // select the menu show at the top of the next page.
1399 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= EndRow
; ) {
1400 Link
= Link
->BackLink
;
1402 // Already find the first menu in this form, means highlight menu
1403 // will show in first page of this form.
1405 if (Link
== &gMenuOption
) {
1406 *TopOfScreen
= gMenuOption
.ForwardLink
;
1410 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1411 UpdateOptionSkipLines (SavedMenuOption
);
1412 Index
+= SavedMenuOption
->Skip
;
1416 // Found the menu which will show at the top of the page.
1418 if (Link
== NewPos
) {
1420 // The menu can show more than one pages, just show the menu at the top of the page.
1423 *TopOfScreen
= Link
;
1426 // Check whether need to skip some line for menu shows at the top of the page.
1428 *SkipValue
= Index
- EndRow
;
1429 if (*SkipValue
> 0 && *SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
1430 *TopOfScreen
= Link
;
1433 *TopOfScreen
= Link
->ForwardLink
;
1439 Display menu and wait for user to select one menu option, then return it.
1440 If AutoBoot is enabled, then if user doesn't select any option,
1441 after period of time, it will automatically return the first menu option.
1443 @param FormData The current form data info.
1445 @retval EFI_SUCESSS Process the user selection success.
1446 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
1451 IN FORM_DISPLAY_ENGINE_FORM
*FormData
1456 UINTN DistanceValue
;
1469 CHAR16
*OptionString
;
1470 CHAR16
*OutputString
;
1472 CHAR16
*HelpHeaderString
;
1473 CHAR16
*HelpBottomString
;
1482 LIST_ENTRY
*TopOfScreen
;
1483 LIST_ENTRY
*SavedListEntry
;
1484 UI_MENU_OPTION
*MenuOption
;
1485 UI_MENU_OPTION
*NextMenuOption
;
1486 UI_MENU_OPTION
*SavedMenuOption
;
1487 UI_MENU_OPTION
*PreviousMenuOption
;
1488 UI_CONTROL_FLAG ControlFlag
;
1489 UI_SCREEN_OPERATION ScreenOperation
;
1491 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1492 UINTN ModalSkipColumn
;
1493 BROWSER_HOT_KEY
*HotKey
;
1494 UINTN HelpPageIndex
;
1495 UINTN HelpPageCount
;
1498 UINTN HelpHeaderLine
;
1499 UINTN HelpBottomLine
;
1500 BOOLEAN MultiHelpPage
;
1502 UINT16 EachLineWidth
;
1503 UINT16 HeaderLineWidth
;
1504 UINT16 BottomLineWidth
;
1505 EFI_STRING_ID HelpInfo
;
1506 UI_EVENT_TYPE EventType
;
1507 FORM_DISPLAY_ENGINE_STATEMENT
*InitialHighlight
;
1509 EventType
= UIEventNone
;
1510 Status
= EFI_SUCCESS
;
1512 HelpHeaderString
= NULL
;
1513 HelpBottomString
= NULL
;
1514 OptionString
= NULL
;
1515 ScreenOperation
= UiNoOperation
;
1524 MultiHelpPage
= FALSE
;
1526 HeaderLineWidth
= 0;
1527 BottomLineWidth
= 0;
1528 OutputString
= NULL
;
1533 NextMenuOption
= NULL
;
1534 PreviousMenuOption
= NULL
;
1535 SavedMenuOption
= NULL
;
1539 ModalSkipColumn
= (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
1540 InitialHighlight
= gFormData
->HighLightedStatement
;
1542 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1544 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3);
1545 gPromptBlockWidth
= (CHAR16
) (gOptionBlockWidth
+ LEFT_SKIPPED_COLUMNS
);
1546 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- LEFT_SKIPPED_COLUMNS
);
1548 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1549 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
1552 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1553 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1555 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1558 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
1560 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1562 ControlFlag
= CfInitialization
;
1564 switch (ControlFlag
) {
1565 case CfInitialization
:
1566 if (IsListEmpty (&gMenuOption
)) {
1568 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) == 0) {
1570 // Clear Statement range.
1573 gStatementDimensions
.LeftColumn
,
1574 gStatementDimensions
.RightColumn
,
1575 TopRow
- SCROLL_ARROW_HEIGHT
,
1576 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1577 GetFieldTextColor ()
1583 RefreshKeyHelp (gFormData
, NULL
, FALSE
);
1586 ControlFlag
= CfReadKey
;
1588 ControlFlag
= CfRepaint
;
1593 ControlFlag
= CfRefreshHighLight
;
1603 Temp
= (UINTN
) SkipValue
;
1604 Temp2
= (UINTN
) SkipValue
;
1605 Temp3
= (UINTN
) SkipValue
;
1608 // 1. Clear the screen.
1610 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1612 gStatementDimensions
.LeftColumn
+ ModalSkipColumn
,
1613 gStatementDimensions
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1614 TopRow
- SCROLL_ARROW_HEIGHT
,
1615 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1616 GetFieldTextColor ()
1619 TempRightCol
= gStatementDimensions
.RightColumn
;
1620 if (!mStatementLayoutIsChanged
) {
1621 TempRightCol
= gStatementDimensions
.RightColumn
- gHelpBlockWidth
;
1624 gStatementDimensions
.LeftColumn
,
1625 gStatementDimensions
.RightColumn
,
1626 TopRow
- SCROLL_ARROW_HEIGHT
,
1628 GetFieldTextColor ()
1631 gStatementDimensions
.LeftColumn
,
1635 GetFieldTextColor ()
1638 gStatementDimensions
.LeftColumn
,
1639 gStatementDimensions
.RightColumn
,
1641 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1642 GetFieldTextColor ()
1647 // 2.Paint the menu.
1649 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1650 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1651 MenuOption
->Row
= Row
;
1652 MenuOption
->Col
= Col
;
1653 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1654 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + gStatementDimensions
.LeftColumn
+ ModalSkipColumn
;
1656 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + gStatementDimensions
.LeftColumn
;
1659 Statement
= MenuOption
->ThisTag
;
1660 if (MenuOption
->NestInStatement
) {
1661 MenuOption
->Col
+= SUBTITLE_INDENT
;
1664 if (MenuOption
->GrayOut
) {
1665 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1667 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1668 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1672 Width
= GetWidth (Statement
);
1676 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1678 // Print Arrow for Goto button.
1681 MenuOption
->Col
- 2,
1683 GEOMETRICSHAPE_RIGHT_TRIANGLE
1688 // 2.1. Paint the description.
1690 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1692 // Temp means need to skip how many lines from the start.
1694 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1695 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1698 // If there is more string to process print on the next row and increment the Skip value
1700 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1706 FreePool (OutputString
);
1716 // 2.2. Paint the option string.
1718 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
1720 // If Error occur, question value update in ProcessOptions.
1721 // Exit current FormDisplay with new question value.
1723 if (EFI_ERROR (Status
)) {
1727 if (OptionString
!= NULL
) {
1728 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1729 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
1732 Width
= (UINT16
) gOptionBlockWidth
;
1736 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1737 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1738 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1741 // If there is more string to process print on the next row and increment the Skip value
1743 if (StrLen (&OptionString
[Index
]) != 0) {
1747 // Since the Number of lines for this menu entry may or may not be reflected accurately
1748 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1749 // some testing to ensure we are keeping this in-sync.
1751 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1753 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1759 FreePool (OutputString
);
1767 FreePool (OptionString
);
1772 // If this is a text op with secondary text information
1774 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1775 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1777 Width
= (UINT16
) gOptionBlockWidth
;
1781 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1782 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
1783 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1786 // If there is more string to process print on the next row and increment the Skip value
1788 if (StrLen (&StringPtr
[Index
]) != 0) {
1792 // Since the Number of lines for this menu entry may or may not be reflected accurately
1793 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1794 // some testing to ensure we are keeping this in-sync.
1796 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1798 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1804 FreePool (OutputString
);
1811 FreePool (StringPtr
);
1815 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1818 // 3. Update the row info which will be used by next menu.
1820 if (Link
== TopOfScreen
) {
1821 Row
+= MenuOption
->Skip
- SkipValue
;
1823 Row
+= MenuOption
->Skip
;
1826 if (Row
> BottomRow
) {
1827 if (!ValueIsScroll (FALSE
, Link
)) {
1831 Row
= BottomRow
+ 1;
1836 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1841 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
1843 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1844 TopRow
- SCROLL_ARROW_HEIGHT
,
1847 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1851 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
1853 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1854 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1857 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1864 case CfRefreshHighLight
:
1867 // MenuOption: Last menu option that need to remove hilight
1868 // MenuOption is set to NULL in Repaint
1869 // NewPos: Current menu option that need to hilight
1871 ControlFlag
= CfUpdateHelpString
;
1873 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
1878 if (NewPos
== TopOfScreen
) {
1884 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
1885 if (MenuOption
!= NULL
) {
1887 // Remove highlight on last Menu Option
1889 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1890 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
1891 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1892 if (OptionString
!= NULL
) {
1893 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1894 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
1896 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
1899 Width
= (UINT16
) gOptionBlockWidth
;
1900 OriginalRow
= MenuOption
->Row
;
1903 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1904 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
1905 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1908 // If there is more string to process print on the next row and increment the Skip value
1910 if (StrLen (&OptionString
[Index
]) != 0) {
1916 FreePool (OutputString
);
1922 MenuOption
->Row
= OriginalRow
;
1924 FreePool (OptionString
);
1927 if (MenuOption
->GrayOut
) {
1928 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1929 } else if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1930 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1933 OriginalRow
= MenuOption
->Row
;
1934 Width
= GetWidth (MenuOption
->ThisTag
);
1937 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1938 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
1939 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
1942 // If there is more string to process print on the next row and increment the Skip value
1944 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1950 FreePool (OutputString
);
1956 MenuOption
->Row
= OriginalRow
;
1957 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1963 // This is the current selected statement
1965 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1966 Statement
= MenuOption
->ThisTag
;
1969 // Get the highlight statement.
1971 gUserInput
->SelectedStatement
= Statement
;
1972 gSequence
= (UINT16
) MenuOption
->Sequence
;
1975 // Record highlight row info for date/time opcode.
1977 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1978 gHighligthMenuInfo
.QuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1979 gHighligthMenuInfo
.DisplayRow
= (UINT16
) MenuOption
->Row
;
1981 gHighligthMenuInfo
.QuestionId
= 0;
1982 gHighligthMenuInfo
.DisplayRow
= 0;
1985 if (!IsSelectable (MenuOption
)) {
1986 RefreshKeyHelp(gFormData
, Statement
, FALSE
);
1991 // Set reverse attribute
1993 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1994 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1996 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
1997 if (OptionString
!= NULL
) {
1998 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1999 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2001 Width
= (UINT16
) gOptionBlockWidth
;
2003 OriginalRow
= MenuOption
->Row
;
2006 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2007 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2008 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2011 // If there is more string to process print on the next row and increment the Skip value
2013 if (StrLen (&OptionString
[Index
]) != 0) {
2019 FreePool (OutputString
);
2025 MenuOption
->Row
= OriginalRow
;
2027 FreePool (OptionString
);
2030 OriginalRow
= MenuOption
->Row
;
2032 Width
= GetWidth (Statement
);
2035 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2036 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2037 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2040 // If there is more string to process print on the next row and increment the Skip value
2042 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2048 FreePool (OutputString
);
2054 MenuOption
->Row
= OriginalRow
;
2059 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2062 // Clear reverse attribute
2064 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2068 case CfUpdateHelpString
:
2069 ControlFlag
= CfPrepareToReadKey
;
2070 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2074 if (Repaint
|| NewLine
) {
2076 // Don't print anything if it is a NULL help token
2078 ASSERT(MenuOption
!= NULL
);
2079 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2080 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2081 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2083 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2086 RowCount
= BottomRow
- TopRow
+ 1;
2089 // 1.Calculate how many line the help string need to print.
2091 if (HelpString
!= NULL
) {
2092 FreePool (HelpString
);
2095 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2096 FreePool (StringPtr
);
2098 if (HelpLine
> RowCount
) {
2099 MultiHelpPage
= TRUE
;
2100 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2101 if (HelpHeaderString
!= NULL
) {
2102 FreePool (HelpHeaderString
);
2103 HelpHeaderString
= NULL
;
2105 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2106 FreePool (StringPtr
);
2107 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2108 if (HelpBottomString
!= NULL
) {
2109 FreePool (HelpBottomString
);
2110 HelpBottomString
= NULL
;
2112 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2113 FreePool (StringPtr
);
2115 // Calculate the help page count.
2117 if (HelpLine
> 2 * RowCount
- 2) {
2118 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2119 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
2126 MultiHelpPage
= FALSE
;
2131 // Check whether need to show the 'More(U/u)' at the begin.
2132 // Base on current direct info, here shows aligned to the right side of the column.
2133 // If the direction is multi line and aligned to right side may have problem, so
2134 // add ASSERT code here.
2136 if (HelpPageIndex
> 0) {
2137 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2138 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2139 ASSERT (HelpHeaderLine
== 1);
2140 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2141 PrintStringAtWithWidth (
2142 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2148 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2150 &HelpHeaderString
[Index
* HeaderLineWidth
]
2155 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
2157 // Print the help string info.
2159 if (!MultiHelpPage
) {
2160 for (Index
= 0; Index
< HelpLine
; Index
++) {
2161 PrintStringAtWithWidth (
2162 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2164 &HelpString
[Index
* EachLineWidth
],
2168 for (; Index
< RowCount
; Index
++) {
2169 PrintStringAtWithWidth (
2170 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2176 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2178 if (HelpPageIndex
== 0) {
2179 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
2180 PrintStringAtWithWidth (
2181 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2183 &HelpString
[Index
* EachLineWidth
],
2188 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
2189 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
2190 PrintStringAtWithWidth (
2191 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2192 Index
+ TopRow
+ HelpHeaderLine
,
2193 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
2197 if (HelpPageIndex
== HelpPageCount
- 1) {
2198 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
2199 PrintStringAtWithWidth (
2200 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2201 Index
+ TopRow
+ HelpHeaderLine
,
2206 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2212 // Check whether need to print the 'More(D/d)' at the bottom.
2213 // Base on current direct info, here shows aligned to the right side of the column.
2214 // If the direction is multi line and aligned to right side may have problem, so
2215 // add ASSERT code here.
2217 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
2218 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2219 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
2220 ASSERT (HelpBottomLine
== 1);
2221 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2222 PrintStringAtWithWidth (
2223 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2224 BottomRow
+ Index
- HelpBottomLine
+ 1,
2229 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
2230 BottomRow
+ Index
- HelpBottomLine
+ 1,
2231 &HelpBottomString
[Index
* BottomLineWidth
]
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
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2255 if (!EFI_ERROR (Status
)) {
2256 EventType
= UIEventKey
;
2261 // If we encounter error, continue to read another key in.
2263 if (Status
!= EFI_NOT_READY
) {
2267 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
2268 if (EventType
== UIEventKey
) {
2269 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2274 if (EventType
== UIEventDriver
) {
2275 gUserInput
->Action
= BROWSER_ACTION_NONE
;
2276 ControlFlag
= CfExit
;
2280 if (EventType
== UIEventTimeOut
) {
2281 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2282 ControlFlag
= CfExit
;
2286 switch (Key
.UnicodeChar
) {
2287 case CHAR_CARRIAGE_RETURN
:
2288 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2289 ControlFlag
= CfReadKey
;
2293 ScreenOperation
= UiSelect
;
2298 // We will push the adjustment of these numeric values directly to the input handler
2299 // NOTE: we won't handle manual input numeric
2304 // If the screen has no menu items, and the user didn't select UiReset
2305 // ignore the selection and go back to reading keys.
2307 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2308 ControlFlag
= CfReadKey
;
2312 ASSERT(MenuOption
!= NULL
);
2313 Statement
= MenuOption
->ThisTag
;
2314 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
2315 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2316 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
2318 if (Key
.UnicodeChar
== '+') {
2319 gDirection
= SCAN_RIGHT
;
2321 gDirection
= SCAN_LEFT
;
2324 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2325 if (OptionString
!= NULL
) {
2326 FreePool (OptionString
);
2328 if (EFI_ERROR (Status
)) {
2330 // Repaint to clear possible error prompt pop-up
2335 ControlFlag
= CfExit
;
2341 ScreenOperation
= UiUp
;
2346 ScreenOperation
= UiDown
;
2350 if(IsListEmpty (&gMenuOption
)) {
2351 ControlFlag
= CfReadKey
;
2355 ASSERT(MenuOption
!= NULL
);
2356 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
2357 ScreenOperation
= UiSelect
;
2363 if (!MultiHelpPage
) {
2364 ControlFlag
= CfReadKey
;
2367 ControlFlag
= CfUpdateHelpString
;
2368 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
2373 if (!MultiHelpPage
) {
2374 ControlFlag
= CfReadKey
;
2377 ControlFlag
= CfUpdateHelpString
;
2378 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
2382 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2383 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2384 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2389 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2391 // ModalForm has no ESC key and Hot Key.
2393 ControlFlag
= CfReadKey
;
2394 } else if (Index
== mScanCodeNumber
) {
2396 // Check whether Key matches the registered hot key.
2399 HotKey
= GetHotKeyFromRegisterList (&Key
);
2400 if (HotKey
!= NULL
) {
2401 ScreenOperation
= UiHotKey
;
2408 case CfScreenOperation
:
2409 if (ScreenOperation
!= UiReset
) {
2411 // If the screen has no menu items, and the user didn't select UiReset
2412 // ignore the selection and go back to reading keys.
2414 if (IsListEmpty (&gMenuOption
)) {
2415 ControlFlag
= CfReadKey
;
2421 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2424 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2425 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2432 ControlFlag
= CfRepaint
;
2434 ASSERT(MenuOption
!= NULL
);
2435 Statement
= MenuOption
->ThisTag
;
2436 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2440 switch (Statement
->OpCode
->OpCode
) {
2441 case EFI_IFR_REF_OP
:
2442 case EFI_IFR_ACTION_OP
:
2443 case EFI_IFR_RESET_BUTTON_OP
:
2444 ControlFlag
= CfExit
;
2449 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2451 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
2452 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2454 if (OptionString
!= NULL
) {
2455 FreePool (OptionString
);
2458 if (EFI_ERROR (Status
)) {
2461 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
2464 ControlFlag
= CfExit
;
2472 // We come here when someone press ESC
2473 // If the policy is not exit front page when user press ESC, process here.
2475 if (!FormExitPolicy()) {
2478 ControlFlag
= CfRepaint
;
2483 // When user press ESC, it will try to show another menu, should clean the gSequence info.
2485 if (gSequence
!= 0) {
2489 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2490 ControlFlag
= CfExit
;
2494 ControlFlag
= CfRepaint
;
2496 gUserInput
->Action
= HotKey
->Action
;
2497 ControlFlag
= CfExit
;
2501 ControlFlag
= CfRepaint
;
2502 ASSERT(MenuOption
!= NULL
);
2503 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2504 if (MenuOption
->Sequence
!= 0) {
2506 // In the middle or tail of the Date/Time op-code set, go left.
2508 ASSERT(NewPos
!= NULL
);
2509 NewPos
= NewPos
->BackLink
;
2515 ControlFlag
= CfRepaint
;
2516 ASSERT(MenuOption
!= NULL
);
2517 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2518 if (MenuOption
->Sequence
!= 2) {
2520 // In the middle or tail of the Date/Time op-code set, go left.
2522 ASSERT(NewPos
!= NULL
);
2523 NewPos
= NewPos
->ForwardLink
;
2529 ControlFlag
= CfRepaint
;
2531 SavedListEntry
= NewPos
;
2533 ASSERT(NewPos
!= NULL
);
2535 // Adjust Date/Time position before we advance forward.
2537 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2538 if (NewPos
->BackLink
!= &gMenuOption
) {
2539 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2540 ASSERT (MenuOption
!= NULL
);
2542 NewPos
= NewPos
->BackLink
;
2544 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2545 if (PreviousMenuOption
->Row
== 0) {
2546 UpdateOptionSkipLines (PreviousMenuOption
);
2548 DistanceValue
= PreviousMenuOption
->Skip
;
2550 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2551 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2553 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2555 if (Difference
< 0) {
2557 // We hit the begining MenuOption that can be focused
2558 // so we simply scroll to the top.
2560 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2561 TopOfScreen
= gMenuOption
.ForwardLink
;
2565 // Scroll up to the last page when we have arrived at top page.
2567 NewPos
= &gMenuOption
;
2568 TopOfScreen
= &gMenuOption
;
2569 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2570 ScreenOperation
= UiPageUp
;
2571 ControlFlag
= CfScreenOperation
;
2574 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2576 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2578 TopOfScreen
= NewPos
;
2581 } else if (!IsSelectable (NextMenuOption
)) {
2583 // Continue to go up until scroll to next page or the selectable option is found.
2585 ScreenOperation
= UiUp
;
2586 ControlFlag
= CfScreenOperation
;
2590 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2592 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2593 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2594 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2595 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2598 // Scroll up to the last page.
2600 NewPos
= &gMenuOption
;
2601 TopOfScreen
= &gMenuOption
;
2602 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2603 ScreenOperation
= UiPageUp
;
2604 ControlFlag
= CfScreenOperation
;
2610 // SkipValue means lines is skipped when show the top menu option.
2612 ControlFlag
= CfRepaint
;
2614 ASSERT(NewPos
!= NULL
);
2616 // Already at the first menu option, Check the skip value.
2618 if (NewPos
->BackLink
== &gMenuOption
) {
2619 if (SkipValue
== 0) {
2634 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
2635 // form of options to be show, so just update the SkipValue to show the next
2636 // parts of options.
2638 if (SkipValue
> (INTN
) (BottomRow
- TopRow
+ 1)) {
2639 SkipValue
-= BottomRow
- TopRow
+ 1;
2645 // First minus the menu of the top screen, it's value is SkipValue.
2647 Index
= (BottomRow
+ 1) - SkipValue
;
2648 while ((Index
> TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2649 Link
= Link
->BackLink
;
2650 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2651 if (PreviousMenuOption
->Row
== 0) {
2652 UpdateOptionSkipLines (PreviousMenuOption
);
2654 if (Index
< PreviousMenuOption
->Skip
) {
2657 Index
= Index
- PreviousMenuOption
->Skip
;
2660 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2662 if (TopOfScreen
== &gMenuOption
) {
2663 TopOfScreen
= gMenuOption
.ForwardLink
;
2664 NewPos
= gMenuOption
.BackLink
;
2665 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2667 } else if (TopOfScreen
!= Link
) {
2670 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2673 // Finally we know that NewPos is the last MenuOption can be focused.
2677 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2680 if (Index
> TopRow
) {
2682 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
2684 SkipValue
= PreviousMenuOption
->Skip
- (Index
- TopRow
);
2685 } else if (Index
== TopRow
) {
2688 SkipValue
= TopRow
- Index
;
2692 // Move to the option in Next page.
2694 if (TopOfScreen
== &gMenuOption
) {
2695 NewPos
= gMenuOption
.BackLink
;
2696 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2699 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2703 // There are more MenuOption needing scrolling up.
2710 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2711 // Don't do this when we are already in the first page.
2713 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2714 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2719 // SkipValue means lines is skipped when show the top menu option.
2721 ControlFlag
= CfRepaint
;
2723 ASSERT (NewPos
!= NULL
);
2724 if (NewPos
->ForwardLink
== &gMenuOption
) {
2733 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2734 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
2736 // Count to the menu option which will show at the top of the next form.
2738 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
2739 Link
= Link
->ForwardLink
;
2740 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2741 Index
= Index
+ NextMenuOption
->Skip
;
2744 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
2746 // Finally we know that NewPos is the last MenuOption can be focused.
2749 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2752 // Calculate the skip line for top of screen menu.
2754 if (Link
== TopOfScreen
) {
2756 // The top of screen menu option occupies the entire form.
2758 SkipValue
+= BottomRow
- TopRow
+ 1;
2760 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
2766 // Move to the Next selectable menu.
2768 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
2772 // Save the menu as the next highlight menu.
2777 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2778 // Don't do this when we are already in the last page.
2780 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2781 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2786 // SkipValue means lines is skipped when show the top menu option.
2787 // NewPos points to the menu which is highlighted now.
2789 ControlFlag
= CfRepaint
;
2792 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2793 // to be one that progresses to the next set of op-codes, we need to advance to the last
2794 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2795 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2796 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2797 // the Date/Time op-code.
2799 SavedListEntry
= NewPos
;
2800 AdjustDateAndTimePosition (FALSE
, &NewPos
);
2802 if (NewPos
->ForwardLink
!= &gMenuOption
) {
2803 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2805 NewPos
= NewPos
->ForwardLink
;
2809 // Current menu not at the bottom of the form.
2811 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
2813 // Find the next selectable menu.
2815 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
2817 // We hit the end of MenuOption that can be focused
2818 // so we simply scroll to the first page.
2820 if (Difference
< 0) {
2822 // Scroll to the first page.
2824 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2825 TopOfScreen
= gMenuOption
.ForwardLink
;
2829 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2831 NewPos
= gMenuOption
.ForwardLink
;
2832 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2836 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2838 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2839 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2843 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2844 if (NextMenuOption
->Row
== 0) {
2845 UpdateOptionSkipLines (NextMenuOption
);
2847 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
2849 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
2850 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
2851 (NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
||
2852 NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2858 // If we are going to scroll, update TopOfScreen
2860 if (Temp
> BottomRow
) {
2863 // Is the current top of screen a zero-advance op-code?
2864 // If so, keep moving forward till we hit a >0 advance op-code
2866 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2869 // If bottom op-code is more than one line or top op-code is more than one line
2871 if ((DistanceValue
> 1) || (SavedMenuOption
->Skip
> 1)) {
2873 // Is the bottom op-code greater than or equal in size to the top op-code?
2875 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
2877 // Skip the top op-code
2879 TopOfScreen
= TopOfScreen
->ForwardLink
;
2880 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
2882 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2885 // If we have a remainder, skip that many more op-codes until we drain the remainder
2887 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
2889 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2891 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
2892 TopOfScreen
= TopOfScreen
->ForwardLink
;
2893 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2896 // Since we will act on this op-code in the next routine, and increment the
2897 // SkipValue, set the skips to one less than what is required.
2899 SkipValue
= Difference
- 1;
2902 // Since we will act on this op-code in the next routine, and increment the
2903 // SkipValue, set the skips to one less than what is required.
2905 SkipValue
+= (Temp
- BottomRow
) - 1;
2908 if ((SkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2909 TopOfScreen
= TopOfScreen
->ForwardLink
;
2914 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2915 // Let's set a skip flag to smoothly scroll the top of the screen.
2917 if (SavedMenuOption
->Skip
> 1) {
2918 if (SavedMenuOption
== NextMenuOption
) {
2923 } else if (SavedMenuOption
->Skip
== 1) {
2927 TopOfScreen
= TopOfScreen
->ForwardLink
;
2929 } while (SavedMenuOption
->Skip
== 0);
2932 } else if (!IsSelectable (NextMenuOption
)) {
2934 // Continue to go down until scroll to next page or the selectable option is found.
2936 ScreenOperation
= UiDown
;
2937 ControlFlag
= CfScreenOperation
;
2940 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2942 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2946 // Scroll to the first page.
2948 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2949 TopOfScreen
= gMenuOption
.ForwardLink
;
2954 // Need to remove the current highlight menu.
2955 // MenuOption saved the last highlight menu info.
2957 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2963 // Get the next highlight menu.
2965 NewPos
= gMenuOption
.ForwardLink
;
2966 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2970 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2972 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2973 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2976 case CfUiNoOperation
:
2977 ControlFlag
= CfRepaint
;
2981 if (HelpString
!= NULL
) {
2982 FreePool (HelpString
);
2984 if (HelpHeaderString
!= NULL
) {
2985 FreePool (HelpHeaderString
);
2987 if (HelpBottomString
!= NULL
) {
2988 FreePool (HelpBottomString
);
3000 Base on the browser status info to show an pop up message.
3004 BrowserStatusProcess (
3011 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3015 if (gFormData
->ErrorString
!= NULL
) {
3016 ErrorInfo
= gFormData
->ErrorString
;
3018 switch (gFormData
->BrowserStatus
) {
3019 case BROWSER_SUBMIT_FAIL
:
3020 ErrorInfo
= gSaveFailed
;
3023 case BROWSER_NO_SUBMIT_IF
:
3024 ErrorInfo
= gNoSubmitIf
;
3027 case BROWSER_FORM_NOT_FOUND
:
3028 ErrorInfo
= gFormNotFound
;
3031 case BROWSER_FORM_SUPPRESS
:
3032 ErrorInfo
= gFormSuppress
;
3035 case BROWSER_PROTOCOL_NOT_FOUND
:
3036 ErrorInfo
= gProtocolNotFound
;
3040 ErrorInfo
= gBrwoserError
;
3046 // Error occur, prompt error message.
3049 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3050 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3054 Display one form, and return user input.
3056 @param FormData Form Data to be shown.
3057 @param UserInputData User input data.
3059 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
3060 2.Error info has show and return.
3061 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
3062 @retval EFI_NOT_FOUND New form data has some error.
3067 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
3068 OUT USER_INPUT
*UserInputData
3073 ASSERT (FormData
!= NULL
);
3074 if (FormData
== NULL
) {
3075 return EFI_INVALID_PARAMETER
;
3078 gUserInput
= UserInputData
;
3079 gFormData
= FormData
;
3082 // Process the status info first.
3084 BrowserStatusProcess();
3085 if (UserInputData
== NULL
) {
3087 // UserInputData == NULL, means only need to print the error info, return here.
3092 ConvertStatementToMenu();
3094 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
3095 if (EFI_ERROR (Status
)) {
3099 if (CompareMem (&gOldStatementDimensions
, &gStatementDimensions
, sizeof (gStatementDimensions
)) == 0) {
3100 mStatementLayoutIsChanged
= FALSE
;
3102 mStatementLayoutIsChanged
= TRUE
;
3103 CopyMem (&gOldStatementDimensions
, &gStatementDimensions
, sizeof (gStatementDimensions
));
3106 Status
= UiDisplayMenu(FormData
);
3112 Initialize Setup Browser driver.
3114 @param ImageHandle The image handle.
3115 @param SystemTable The system table.
3117 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
3118 @return Other value if failed to initialize the Setup Browser module.
3123 InitializeDisplayEngine (
3124 IN EFI_HANDLE ImageHandle
,
3125 IN EFI_SYSTEM_TABLE
*SystemTable
3129 EFI_INPUT_KEY HotKey
;
3130 EFI_STRING NewString
;
3131 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
3134 // Publish our HII data
3136 gHiiHandle
= HiiAddPackages (
3137 &gDisplayEngineGuid
,
3139 DisplayEngineStrings
,
3142 ASSERT (gHiiHandle
!= NULL
);
3145 // Install Form Display protocol
3147 Status
= gBS
->InstallProtocolInterface (
3148 &mPrivateData
.Handle
,
3149 &gEdkiiFormDisplayEngineProtocolGuid
,
3150 EFI_NATIVE_INTERFACE
,
3151 &mPrivateData
.FromDisplayProt
3153 ASSERT_EFI_ERROR (Status
);
3155 InitializeDisplayStrings();
3158 // Use BrowserEx2 protocol to register HotKey.
3160 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
3161 if (!EFI_ERROR (Status
)) {
3163 // Register the default HotKey F9 and F10 again.
3165 HotKey
.UnicodeChar
= CHAR_NULL
;
3166 HotKey
.ScanCode
= SCAN_F10
;
3167 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
3168 ASSERT (NewString
!= NULL
);
3169 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
3171 HotKey
.ScanCode
= SCAN_F9
;
3172 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
3173 ASSERT (NewString
!= NULL
);
3174 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
3181 This is the default unload handle for display core drivers.
3183 @param[in] ImageHandle The drivers' driver image.
3185 @retval EFI_SUCCESS The image is unloaded.
3186 @retval Others Failed to unload the image.
3191 UnloadDisplayEngine (
3192 IN EFI_HANDLE ImageHandle
3195 HiiRemovePackages(gHiiHandle
);
3197 FreeDisplayStrings ();