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}
100 FORM_ENTRY_INFO gFormEntryInfo
;
102 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
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};
110 BOOLEAN mIsFirstForm
= TRUE
;
111 FORM_ENTRY_INFO gOldFormEntry
= {0};
114 // Browser Global Strings
116 CHAR16
*gFormNotFound
;
118 CHAR16
*gBrwoserError
;
120 CHAR16
*gPromptForData
;
121 CHAR16
*gPromptForPassword
;
122 CHAR16
*gPromptForNewPassword
;
123 CHAR16
*gConfirmPassword
;
124 CHAR16
*gConfirmError
;
125 CHAR16
*gPassowordInvalid
;
127 CHAR16
*gEmptyString
;
129 CHAR16
*gOptionMismatch
;
130 CHAR16
*gFormSuppress
;
131 CHAR16
*gProtocolNotFound
;
133 CHAR16 gModalSkipColumn
;
134 CHAR16 gPromptBlockWidth
;
135 CHAR16 gOptionBlockWidth
;
136 CHAR16 gHelpBlockWidth
;
137 CHAR16
*mUnknownString
;
139 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
140 FORM_DISPLAY_DRIVER_SIGNATURE
,
144 DriverClearDisplayPage
,
151 Get the string based on the StringId and HII Package List Handle.
153 @param Token The String's ID.
154 @param HiiHandle The package list in the HII database to search for
155 the specified string.
157 @return The output string.
162 IN EFI_STRING_ID Token
,
163 IN EFI_HII_HANDLE HiiHandle
168 String
= HiiGetString (HiiHandle
, Token
, NULL
);
169 if (String
== NULL
) {
170 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
171 ASSERT (String
!= NULL
);
174 return (CHAR16
*) String
;
179 Initialize the HII String Token to the correct values.
183 InitializeDisplayStrings (
187 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
188 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
189 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
190 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
191 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
192 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
193 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
194 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
195 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
196 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
197 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
198 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
199 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
200 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
201 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
202 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
203 gBrwoserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
207 Free up the resource allocated for all strings required
216 FreePool (mUnknownString
);
217 FreePool (gEmptyString
);
218 FreePool (gSaveFailed
);
219 FreePool (gPromptForData
);
220 FreePool (gPromptForPassword
);
221 FreePool (gPromptForNewPassword
);
222 FreePool (gConfirmPassword
);
223 FreePool (gConfirmError
);
224 FreePool (gPassowordInvalid
);
225 FreePool (gPressEnter
);
226 FreePool (gMiniString
);
227 FreePool (gOptionMismatch
);
228 FreePool (gFormSuppress
);
229 FreePool (gProtocolNotFound
);
230 FreePool (gBrwoserError
);
231 FreePool (gNoSubmitIf
);
232 FreePool (gFormNotFound
);
236 Get prompt string id from the opcode data buffer.
238 @param OpCode The input opcode buffer.
240 @return The prompt string id.
245 IN EFI_IFR_OP_HEADER
*OpCode
248 EFI_IFR_STATEMENT_HEADER
*Header
;
250 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
254 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
256 return Header
->Prompt
;
260 Get the supported width for a particular op-code
262 @param Statement The curent statement.
263 @param AdjustWidth The width which is saved for the space.
265 @return Returns the number of CHAR16 characters that is support.
270 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
271 OUT UINT16
*AdjustWidth
276 EFI_IFR_TEXT
*TestOp
;
279 // For modal form, clean the entire row.
281 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
282 if (AdjustWidth
!= NULL
) {
283 *AdjustWidth
= LEFT_SKIPPED_COLUMNS
;
285 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gModalSkipColumn
+ LEFT_SKIPPED_COLUMNS
));
291 // See if the second text parameter is really NULL
293 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
294 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
295 if (TestOp
->TextTwo
!= 0) {
296 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
297 Size
= StrLen (String
);
302 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
303 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
304 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
305 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
306 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
308 // Allow a wide display if text op-code and no secondary text op-code
310 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
314 // Return the space width.
316 if (AdjustWidth
!= NULL
) {
320 // Keep consistent with current behavior.
322 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
325 if (AdjustWidth
!= NULL
) {
328 return (UINT16
) (gPromptBlockWidth
- 1);
332 Will copy LineWidth amount of a string in the OutputString buffer and return the
333 number of CHAR16 characters that were copied into the OutputString buffer.
334 The output string format is:
335 Glyph Info + String info + '\0'.
337 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
339 @param InputString String description for this option.
340 @param LineWidth Width of the desired string to extract in CHAR16
342 @param GlyphWidth The glyph width of the begin of the char in the string.
343 @param Index Where in InputString to start the copy process
344 @param OutputString Buffer to copy the string into
346 @return Returns the number of CHAR16 characters that were copied into the OutputString
347 buffer, include extra glyph info and '\0' info.
352 IN CHAR16
*InputString
,
354 IN OUT UINT16
*GlyphWidth
,
356 OUT CHAR16
**OutputString
361 UINT16 OriginalGlyphWidth
;
363 UINT16 LastSpaceOffset
;
364 UINT16 LastGlyphWidth
;
366 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
370 if (LineWidth
== 0 || *GlyphWidth
== 0) {
375 // Save original glyph width.
377 OriginalGlyphWidth
= *GlyphWidth
;
378 LastGlyphWidth
= OriginalGlyphWidth
;
383 // 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.
384 // To avoid displaying this empty line in screen, just skip the two CHARs here.
386 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
391 // Fast-forward the string and see if there is a carriage-return in the string
393 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
394 switch (InputString
[*Index
+ StrOffset
]) {
403 case CHAR_CARRIAGE_RETURN
:
410 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
413 // Record the last space info in this line. Will be used in rewind.
415 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
416 LastSpaceOffset
= StrOffset
;
417 LastGlyphWidth
= *GlyphWidth
;
428 // Rewind the string from the maximum size until we see a space to break the line
430 if (GlyphOffset
> LineWidth
) {
432 // Rewind the string to last space char in this line.
434 if (LastSpaceOffset
!= 0) {
435 StrOffset
= LastSpaceOffset
;
436 *GlyphWidth
= LastGlyphWidth
;
439 // Roll back to last char in the line width.
446 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
448 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
453 // Need extra glyph info and '\0' info, so +2.
455 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
456 if (*OutputString
== NULL
) {
461 // Save the glyph info at the begin of the string, will used by Print function.
463 if (OriginalGlyphWidth
== 1) {
464 *(*OutputString
) = NARROW_CHAR
;
466 *(*OutputString
) = WIDE_CHAR
;
469 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
471 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
473 // Skip the space info at the begin of next line.
475 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
476 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
478 // Skip the /n or /n/r info.
480 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
481 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
483 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
485 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
487 // Skip the /r or /r/n info.
489 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
490 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
492 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
495 *Index
= (UINT16
) (*Index
+ StrOffset
);
499 // Include extra glyph info and '\0' info, so +2.
501 return StrOffset
+ 2;
505 Add one menu option by specified description and context.
507 @param Statement Statement of this Menu Option.
508 @param MenuItemCount The index for this Option in the Menu.
509 @param NestIn Whether this statement is nest in another statement.
514 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
515 IN UINT16
*MenuItemCount
,
519 UI_MENU_OPTION
*MenuOption
;
523 UINT16 NumberOfLines
;
527 CHAR16
*OutputString
;
528 EFI_STRING_ID PromptId
;
536 PromptId
= GetPrompt (Statement
->OpCode
);
537 ASSERT (PromptId
!= 0);
539 String
= GetToken (PromptId
, gFormData
->HiiHandle
);
540 ASSERT (String
!= NULL
);
542 Width
= GetWidth (Statement
, NULL
);
543 for (; GetLineByWidth (String
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
545 // If there is more string to process print on the next row and increment the Skip value
547 if (StrLen (&String
[ArrayEntry
]) != 0) {
550 FreePool (OutputString
);
553 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
555 // Add three MenuOptions for Date/Time
556 // Data format : [01/02/2004] [11:22:33]
557 // Line number : 0 0 1 0 0 1
563 for (Index
= 0; Index
< Count
; Index
++) {
564 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
567 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
568 MenuOption
->Description
= String
;
569 MenuOption
->Handle
= gFormData
->HiiHandle
;
570 MenuOption
->ThisTag
= Statement
;
571 MenuOption
->NestInStatement
= NestIn
;
572 MenuOption
->EntryNumber
= *MenuItemCount
;
576 // Override LineNumber for the MenuOption in Date/Time sequence
578 MenuOption
->Skip
= 1;
580 MenuOption
->Skip
= NumberOfLines
;
582 MenuOption
->Sequence
= Index
;
584 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
585 MenuOption
->GrayOut
= TRUE
;
587 MenuOption
->GrayOut
= FALSE
;
590 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
591 MenuOption
->GrayOut
= TRUE
;
595 // If the form or the question has the lock attribute, deal same as grayout.
597 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
598 MenuOption
->GrayOut
= TRUE
;
601 switch (Statement
->OpCode
->OpCode
) {
602 case EFI_IFR_ORDERED_LIST_OP
:
603 case EFI_IFR_ONE_OF_OP
:
604 case EFI_IFR_NUMERIC_OP
:
605 case EFI_IFR_TIME_OP
:
606 case EFI_IFR_DATE_OP
:
607 case EFI_IFR_CHECKBOX_OP
:
608 case EFI_IFR_PASSWORD_OP
:
609 case EFI_IFR_STRING_OP
:
611 // User could change the value of these items
613 MenuOption
->IsQuestion
= TRUE
;
615 case EFI_IFR_TEXT_OP
:
616 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
618 // Initializing GrayOut option as TRUE for Text setup options
619 // so that those options will be Gray in colour and un selectable.
621 MenuOption
->GrayOut
= TRUE
;
625 MenuOption
->IsQuestion
= FALSE
;
629 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
630 MenuOption
->ReadOnly
= TRUE
;
631 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
632 MenuOption
->GrayOut
= TRUE
;
636 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
643 Create the menu list base on the form data info.
647 ConvertStatementToMenu (
651 UINT16 MenuItemCount
;
653 LIST_ENTRY
*NestLink
;
654 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
655 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
658 InitializeListHead (&gMenuOption
);
660 Link
= GetFirstNode (&gFormData
->StatementListHead
);
661 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
662 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
663 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
666 // Skip the opcode not recognized by Display core.
668 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
672 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
675 // Check the statement nest in this host statement.
677 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
678 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
679 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
680 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
682 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
688 Count the storage space of a Unicode string.
690 This function handles the Unicode string with NARROW_CHAR
691 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
692 does not count in the resultant output. If a WIDE_CHAR is
693 hit, then 2 Unicode character will consume an output storage
694 space with size of CHAR16 till a NARROW_CHAR is hit.
696 If String is NULL, then ASSERT ().
698 @param String The input string to be counted.
700 @return Storage space for the input string.
710 UINTN IncrementValue
;
712 ASSERT (String
!= NULL
);
713 if (String
== NULL
) {
723 // Advance to the null-terminator or to the first width directive
726 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
727 Index
++, Count
= Count
+ IncrementValue
732 // We hit the null-terminator, we now have a count
734 if (String
[Index
] == 0) {
738 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
739 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
741 if (String
[Index
] == NARROW_CHAR
) {
743 // Skip to the next character
749 // Skip to the next character
754 } while (String
[Index
] != 0);
757 // Increment by one to include the null-terminator in the size
761 return Count
* sizeof (CHAR16
);
765 Base on the input option string to update the skip value for a menu option.
767 @param MenuOption The MenuOption to be checked.
768 @param OptionString The input option string.
772 UpdateSkipInfoForMenu (
773 IN UI_MENU_OPTION
*MenuOption
,
774 IN CHAR16
*OptionString
780 CHAR16
*OutputString
;
783 Width
= (UINT16
) gOptionBlockWidth
;
787 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
788 if (StrLen (&OptionString
[Index
]) != 0) {
792 FreePool (OutputString
);
795 if ((Row
> MenuOption
->Skip
) &&
796 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
797 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
798 MenuOption
->Skip
= Row
;
803 Update display lines for a Menu Option.
805 @param MenuOption The MenuOption to be checked.
809 UpdateOptionSkipLines (
810 IN UI_MENU_OPTION
*MenuOption
813 CHAR16
*OptionString
;
817 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
818 if (OptionString
!= NULL
) {
819 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
821 FreePool (OptionString
);
824 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
825 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
827 if (OptionString
!= NULL
) {
828 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
830 FreePool (OptionString
);
836 Check whether this Menu Option could be highlighted.
838 This is an internal function.
840 @param MenuOption The MenuOption to be checked.
842 @retval TRUE This Menu Option is selectable.
843 @retval FALSE This Menu Option could not be selected.
848 UI_MENU_OPTION
*MenuOption
851 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
852 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
860 Move to next selectable statement.
862 This is an internal function.
864 @param GoUp The navigation direction. TRUE: up, FALSE: down.
865 @param CurrentPosition Current position.
866 @param GapToTop Gap position to top or bottom.
868 @return The row distance from current MenuOption to next selectable MenuOption.
870 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
871 @retval Value Find the selectable menu, maybe the truly selectable, maybe the l
872 last menu showing at current form.
876 MoveToNextStatement (
878 IN OUT LIST_ENTRY
**CurrentPosition
,
884 UI_MENU_OPTION
*NextMenuOption
;
885 UI_MENU_OPTION
*PreMenuOption
;
888 Pos
= *CurrentPosition
;
889 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
892 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
894 // NextMenuOption->Row == 0 means this menu has not calculate
895 // the NextMenuOption->Skip value yet, just calculate here.
897 if (NextMenuOption
->Row
== 0) {
898 UpdateOptionSkipLines (NextMenuOption
);
901 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
903 // In this case, still can't find the selectable menu,
904 // return the last one in the showing form.
906 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
907 NextMenuOption
= PreMenuOption
;
912 // Current Position doesn't need to be caculated when go up.
913 // Caculate distanct at first when go up
915 Distance
+= NextMenuOption
->Skip
;
918 if (IsSelectable (NextMenuOption
)) {
923 // Arrive at begin of the menu list.
925 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
932 // In this case, still can't find the selectable menu,
933 // return the last one in the showing form.
935 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
936 NextMenuOption
= PreMenuOption
;
940 Distance
+= NextMenuOption
->Skip
;
943 PreMenuOption
= NextMenuOption
;
944 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
947 *CurrentPosition
= &NextMenuOption
->Link
;
953 Process option string for date/time opcode.
955 @param MenuOption Menu option point to date/time.
956 @param OptionString Option string input for process.
957 @param AddOptCol Whether need to update MenuOption->OptCol.
961 ProcessStringForDateTime (
962 UI_MENU_OPTION
*MenuOption
,
963 CHAR16
*OptionString
,
969 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
973 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
975 Statement
= MenuOption
->ThisTag
;
978 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
979 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
980 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
981 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
985 // If leading spaces on OptionString - remove the spaces
987 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
989 // Base on the blockspace to get the option column info.
992 MenuOption
->OptCol
++;
996 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
997 OptionString
[Count
] = OptionString
[Index
];
1000 OptionString
[Count
] = CHAR_NULL
;
1003 // Enable to suppress field in the opcode base on the flag.
1005 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1007 // OptionString format is: <**: **: ****>
1011 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1013 // At this point, only "<**:" in the optionstring.
1014 // Clean the day's ** field, after clean, the format is "< :"
1016 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1017 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1019 // At this point, only "**:" in the optionstring.
1020 // Clean the month's "**" field, after clean, the format is " :"
1022 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1023 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1025 // At this point, only "****>" in the optionstring.
1026 // Clean the year's "****" field, after clean, the format is " >"
1028 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1030 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1032 // OptionString format is: <**: **: **>
1033 // |hour|minute|second|
1036 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1038 // At this point, only "<**:" in the optionstring.
1039 // Clean the hour's ** field, after clean, the format is "< :"
1041 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1042 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1044 // At this point, only "**:" in the optionstring.
1045 // Clean the minute's "**" field, after clean, the format is " :"
1047 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1048 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1050 // At this point, only "**>" in the optionstring.
1051 // Clean the second's "**" field, after clean, the format is " >"
1053 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1060 Adjust Data and Time position accordingly.
1061 Data format : [01/02/2004] [11:22:33]
1062 Line number : 0 0 1 0 0 1
1064 This is an internal function.
1066 @param DirectionUp the up or down direction. False is down. True is
1068 @param CurrentPosition Current position. On return: Point to the last
1069 Option (Year or Second) if up; Point to the first
1070 Option (Month or Hour) if down.
1072 @return Return line number to pad. It is possible that we stand on a zero-advance
1073 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1077 AdjustDateAndTimePosition (
1078 IN BOOLEAN DirectionUp
,
1079 IN OUT LIST_ENTRY
**CurrentPosition
1083 LIST_ENTRY
*NewPosition
;
1084 UI_MENU_OPTION
*MenuOption
;
1085 UINTN PadLineNumber
;
1088 NewPosition
= *CurrentPosition
;
1089 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1091 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1092 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1094 // Calculate the distance from current position to the last Date/Time MenuOption
1097 while (MenuOption
->Skip
== 0) {
1099 NewPosition
= NewPosition
->ForwardLink
;
1100 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1104 NewPosition
= *CurrentPosition
;
1107 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1108 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1109 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1110 // checking can be done.
1112 while (Count
++ < 2) {
1113 NewPosition
= NewPosition
->BackLink
;
1117 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1118 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1119 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1120 // checking can be done.
1122 while (Count
-- > 0) {
1123 NewPosition
= NewPosition
->ForwardLink
;
1127 *CurrentPosition
= NewPosition
;
1130 return PadLineNumber
;
1134 Get step info from numeric opcode.
1136 @param[in] OpCode The input numeric op code.
1138 @return step info for this opcode.
1142 IN EFI_IFR_OP_HEADER
*OpCode
1145 EFI_IFR_NUMERIC
*NumericOp
;
1148 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1150 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1151 case EFI_IFR_NUMERIC_SIZE_1
:
1152 Step
= NumericOp
->data
.u8
.Step
;
1155 case EFI_IFR_NUMERIC_SIZE_2
:
1156 Step
= NumericOp
->data
.u16
.Step
;
1159 case EFI_IFR_NUMERIC_SIZE_4
:
1160 Step
= NumericOp
->data
.u32
.Step
;
1163 case EFI_IFR_NUMERIC_SIZE_8
:
1164 Step
= NumericOp
->data
.u64
.Step
;
1176 Find the registered HotKey based on KeyData.
1178 @param[in] KeyData A pointer to a buffer that describes the keystroke
1179 information for the hot key.
1181 @return The registered HotKey context. If no found, NULL will return.
1184 GetHotKeyFromRegisterList (
1185 IN EFI_INPUT_KEY
*KeyData
1189 BROWSER_HOT_KEY
*HotKey
;
1191 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1192 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1193 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1195 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1199 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1207 Determine if the menu is the last menu that can be selected.
1209 This is an internal function.
1211 @param Direction The scroll direction. False is down. True is up.
1212 @param CurrentPos The current focus.
1214 @return FALSE -- the menu isn't the last menu that can be selected.
1215 @return TRUE -- the menu is the last menu that can be selected.
1220 IN BOOLEAN Direction
,
1221 IN LIST_ENTRY
*CurrentPos
1226 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1228 if (Temp
== &gMenuOption
) {
1236 Wait for a given event to fire, or for an optional timeout to expire.
1238 @param Event The event to wait for
1240 @retval UI_EVENT_TYPE The type of the event which is trigged.
1252 EFI_EVENT TimerEvent
;
1253 EFI_EVENT WaitList
[3];
1254 UI_EVENT_TYPE EventType
;
1257 Timeout
= FormExitTimeout(gFormData
);
1260 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1263 // Set the timer event
1272 WaitList
[0] = Event
;
1274 if (gFormData
->FormRefreshEvent
!= NULL
) {
1275 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1280 WaitList
[EventNum
] = TimerEvent
;
1284 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1285 ASSERT_EFI_ERROR (Status
);
1289 EventType
= UIEventKey
;
1293 if (gFormData
->FormRefreshEvent
!= NULL
) {
1294 EventType
= UIEventDriver
;
1296 ASSERT (Timeout
!= 0 && EventNum
== 2);
1297 EventType
= UIEventTimeOut
;
1302 ASSERT (Index
== 2 && EventNum
== 3);
1303 EventType
= UIEventTimeOut
;
1308 gBS
->CloseEvent (TimerEvent
);
1315 Get question id info from the input opcode header.
1317 @param OpCode The input opcode header pointer.
1319 @retval The question id for this opcode.
1324 IN EFI_IFR_OP_HEADER
*OpCode
1327 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1329 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1333 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1335 return QuestionHeader
->QuestionId
;
1339 Find the first menu which will be show at the top.
1341 @param FormData The data info for this form.
1342 @param TopOfScreen The link_entry pointer to top menu.
1343 @param HighlightMenu The menu which will be highlight.
1344 @param SkipValue The skip value for the top menu.
1349 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1350 OUT LIST_ENTRY
**TopOfScreen
,
1351 OUT LIST_ENTRY
**HighlightMenu
,
1360 UI_MENU_OPTION
*SavedMenuOption
;
1363 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1364 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1367 // If not has input highlight statement, just return the first one in this form.
1369 if (FormData
->HighLightedStatement
== NULL
) {
1370 *TopOfScreen
= gMenuOption
.ForwardLink
;
1371 *HighlightMenu
= gMenuOption
.ForwardLink
;
1372 if (!IsListEmpty (&gMenuOption
)) {
1373 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
);
1380 // Now base on the input highlight menu to find the top menu in this page.
1381 // Will base on the highlight menu show at the bottom to find the top menu.
1383 NewPos
= gMenuOption
.ForwardLink
;
1384 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1386 while ((SavedMenuOption
->ThisTag
!= FormData
->HighLightedStatement
) ||
1387 (SavedMenuOption
->Sequence
!= gSequence
)) {
1388 NewPos
= NewPos
->ForwardLink
;
1389 if (NewPos
== &gMenuOption
) {
1391 // Not Found it, break
1395 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1397 ASSERT (SavedMenuOption
->ThisTag
== FormData
->HighLightedStatement
);
1399 *HighlightMenu
= NewPos
;
1401 AdjustDateAndTimePosition(FALSE
, &NewPos
);
1402 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1403 UpdateOptionSkipLines (SavedMenuOption
);
1406 // If highlight opcode is date/time, keep the highlight row info not change.
1408 if ((SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) &&
1409 (gHighligthMenuInfo
.QuestionId
!= 0) &&
1410 (gHighligthMenuInfo
.QuestionId
== GetQuestionIdInfo(SavedMenuOption
->ThisTag
->OpCode
))) {
1412 // Still show the highlight menu before exit from display engine.
1414 EndRow
= gHighligthMenuInfo
.DisplayRow
+ SavedMenuOption
->Skip
;
1420 // Base on the selected menu will show at the bottome of next page,
1421 // select the menu show at the top of the next page.
1424 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= EndRow
; ) {
1425 Link
= Link
->BackLink
;
1427 // Already find the first menu in this form, means highlight menu
1428 // will show in first page of this form.
1430 if (Link
== &gMenuOption
) {
1431 *TopOfScreen
= gMenuOption
.ForwardLink
;
1435 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1436 UpdateOptionSkipLines (SavedMenuOption
);
1437 Index
+= SavedMenuOption
->Skip
;
1441 // Found the menu which will show at the top of the page.
1443 if (Link
== NewPos
) {
1445 // The menu can show more than one pages, just show the menu at the top of the page.
1448 *TopOfScreen
= Link
;
1451 // Check whether need to skip some line for menu shows at the top of the page.
1453 *SkipValue
= Index
- EndRow
;
1454 if (*SkipValue
> 0 && *SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
1455 *TopOfScreen
= Link
;
1458 *TopOfScreen
= Link
->ForwardLink
;
1464 Update highlight menu info.
1466 @param MenuOption The menu opton which is highlight.
1470 UpdateHighlightMenuInfo (
1471 IN UI_MENU_OPTION
*MenuOption
1474 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1477 // This is the current selected statement
1479 Statement
= MenuOption
->ThisTag
;
1482 // Get the highlight statement.
1484 gUserInput
->SelectedStatement
= Statement
;
1485 gSequence
= (UINT16
) MenuOption
->Sequence
;
1488 // Record highlight row info for date/time opcode.
1490 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1491 gHighligthMenuInfo
.QuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1492 gHighligthMenuInfo
.DisplayRow
= (UINT16
) MenuOption
->Row
;
1494 gHighligthMenuInfo
.QuestionId
= 0;
1495 gHighligthMenuInfo
.DisplayRow
= 0;
1498 RefreshKeyHelp(gFormData
, Statement
, FALSE
);
1502 Update attribut for this menu.
1504 @param MenuOption The menu opton which this attribut used to.
1505 @param Highlight Whether this menu will be highlight.
1509 SetDisplayAttribute (
1510 IN UI_MENU_OPTION
*MenuOption
,
1511 IN BOOLEAN Highlight
1514 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1516 Statement
= MenuOption
->ThisTag
;
1519 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1523 if (MenuOption
->GrayOut
) {
1524 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1526 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1527 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1529 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1535 Print string for this menu option.
1537 @param MenuOption The menu opton which this attribut used to.
1538 @param Col The column that this string will be print at.
1539 @param Row The row that this string will be print at.
1540 @param String The string which need to print.
1541 @param Width The width need to print, if string is less than the
1542 width, the block space will be used.
1543 @param Highlight Whether this menu will be highlight.
1548 IN UI_MENU_OPTION
*MenuOption
,
1553 IN BOOLEAN Highlight
1559 // Print string with normal color.
1562 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
1567 // Print the highlight menu string.
1568 // First print the highlight string.
1570 SetDisplayAttribute(MenuOption
, TRUE
);
1571 Length
= PrintStringAt (Col
, Row
, String
);
1574 // Second, clean the empty after the string.
1576 SetDisplayAttribute(MenuOption
, FALSE
);
1577 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
1581 Print string for this menu option.
1583 @param MenuOption The menu opton which this attribut used to.
1584 @param SkipWidth The skip width between the left to the start of the prompt.
1585 @param BeginCol The begin column for one menu.
1586 @param SkipLine The skip line for this menu.
1587 @param BottomRow The bottom row for this form.
1588 @param Highlight Whether this menu will be highlight.
1590 @retval EFI_SUCESSS Process the user selection success.
1595 IN UI_MENU_OPTION
*MenuOption
,
1600 IN BOOLEAN Highlight
1603 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1608 CHAR16
*OptionString
;
1609 CHAR16
*OutputString
;
1618 UINTN PromptLineNum
;
1621 Statement
= MenuOption
->ThisTag
;
1622 Col
= MenuOption
->Col
;
1623 Row
= MenuOption
->Row
;
1630 // Set default color.
1632 SetDisplayAttribute (MenuOption
, FALSE
);
1635 // 1. Paint the option string.
1637 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
1638 if (EFI_ERROR (Status
)) {
1642 if (OptionString
!= NULL
) {
1643 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1645 // Adjust option string for date/time opcode.
1647 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
1650 Width
= (UINT16
) gOptionBlockWidth
- 1;
1654 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1655 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
1656 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1658 // For date/time question, it has three menu options for this qustion.
1659 // The first/second menu options with the skip value is 0. the last one
1660 // with skip value is 1.
1662 if (MenuOption
->Skip
!= 0) {
1664 // For date/ time, print the last past (year for date and second for time)
1665 // - 7 means skip [##/##/ for date and [##:##: for time.
1667 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
1670 // For date/ time, print the first and second past (year for date and second for time)
1672 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
), Highlight
);
1675 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
1680 // If there is more string to process print on the next row and increment the Skip value
1682 if (StrLen (&OptionString
[Index
]) != 0) {
1686 // Since the Number of lines for this menu entry may or may not be reflected accurately
1687 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1688 // some testing to ensure we are keeping this in-sync.
1690 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1692 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1698 FreePool (OutputString
);
1707 FreePool (OptionString
);
1713 // 2. Pre calculate the skip value.
1715 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1716 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1718 Width
= (UINT16
) gOptionBlockWidth
- 1;
1721 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1722 if (StrLen (&StringPtr
[Index
]) != 0) {
1724 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1728 FreePool (OutputString
);
1732 FreePool (StringPtr
);
1737 // 3. Paint the description.
1739 PromptWidth
= GetWidth (Statement
, &AdjustValue
);
1744 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
1745 while (Temp
++ < MenuOption
->Skip
) {
1746 PrintStringAtWithWidth (BeginCol
, Row
++, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
1749 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1750 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1752 // 1.Clean the start LEFT_SKIPPED_COLUMNS
1754 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
1756 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1758 // Print Arrow for Goto button.
1761 MenuOption
->Col
- 2,
1763 GEOMETRICSHAPE_RIGHT_TRIANGLE
1766 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
1770 // If there is more string to process print on the next row and increment the Skip value
1772 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1778 FreePool (OutputString
);
1787 // Clean the empty prompt line.
1788 // These line is used by option string but not prompt, so clean them here.
1790 Row
= OriginalRow
+ PromptLineNum
;
1791 while (PromptLineNum
+ SkipLine
< MenuOption
->Skip
&& Row
<= BottomRow
) {
1792 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
1801 // 4. If this is a text op with secondary text information
1803 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1804 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1806 Width
= (UINT16
) gOptionBlockWidth
- 1;
1810 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1811 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
1812 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
1815 // If there is more string to process print on the next row and increment the Skip value
1817 if (StrLen (&StringPtr
[Index
]) != 0) {
1823 FreePool (OutputString
);
1830 FreePool (StringPtr
);
1837 Display menu and wait for user to select one menu option, then return it.
1838 If AutoBoot is enabled, then if user doesn't select any option,
1839 after period of time, it will automatically return the first menu option.
1841 @param FormData The current form data info.
1843 @retval EFI_SUCESSS Process the user selection success.
1844 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
1849 IN FORM_DISPLAY_ENGINE_FORM
*FormData
1854 UINTN DistanceValue
;
1865 CHAR16
*OptionString
;
1866 CHAR16
*OutputString
;
1868 CHAR16
*HelpHeaderString
;
1869 CHAR16
*HelpBottomString
;
1878 LIST_ENTRY
*TopOfScreen
;
1879 LIST_ENTRY
*SavedListEntry
;
1880 UI_MENU_OPTION
*MenuOption
;
1881 UI_MENU_OPTION
*NextMenuOption
;
1882 UI_MENU_OPTION
*SavedMenuOption
;
1883 UI_MENU_OPTION
*PreviousMenuOption
;
1884 UI_CONTROL_FLAG ControlFlag
;
1885 UI_SCREEN_OPERATION ScreenOperation
;
1887 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1888 BROWSER_HOT_KEY
*HotKey
;
1889 UINTN HelpPageIndex
;
1890 UINTN HelpPageCount
;
1893 UINTN HelpHeaderLine
;
1894 UINTN HelpBottomLine
;
1895 BOOLEAN MultiHelpPage
;
1897 UINT16 EachLineWidth
;
1898 UINT16 HeaderLineWidth
;
1899 UINT16 BottomLineWidth
;
1900 EFI_STRING_ID HelpInfo
;
1901 UI_EVENT_TYPE EventType
;
1902 FORM_DISPLAY_ENGINE_STATEMENT
*InitialHighlight
;
1903 BOOLEAN SkipHighLight
;
1905 EventType
= UIEventNone
;
1906 Status
= EFI_SUCCESS
;
1908 HelpHeaderString
= NULL
;
1909 HelpBottomString
= NULL
;
1910 OptionString
= NULL
;
1911 ScreenOperation
= UiNoOperation
;
1920 MultiHelpPage
= FALSE
;
1922 HeaderLineWidth
= 0;
1923 BottomLineWidth
= 0;
1924 OutputString
= NULL
;
1928 SkipHighLight
= FALSE
;
1930 NextMenuOption
= NULL
;
1931 PreviousMenuOption
= NULL
;
1932 SavedMenuOption
= NULL
;
1936 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
1937 InitialHighlight
= gFormData
->HighLightedStatement
;
1939 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1943 // |<-.->|<-.........->|<- .........->|<-...........->|
1944 // Skip Prompt Option Help
1946 Width
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3);
1947 gOptionBlockWidth
= Width
+ 1;
1948 gHelpBlockWidth
= (CHAR16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1949 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * Width
- 1);
1951 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1952 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
1955 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1956 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
1958 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1961 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
1963 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1965 ControlFlag
= CfInitialization
;
1967 switch (ControlFlag
) {
1968 case CfInitialization
:
1969 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
1970 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
1972 // Clear Statement range if different formset is painted.
1975 gStatementDimensions
.LeftColumn
,
1976 gStatementDimensions
.RightColumn
,
1977 TopRow
- SCROLL_ARROW_HEIGHT
,
1978 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1979 GetFieldTextColor ()
1983 ControlFlag
= CfRepaint
;
1987 ControlFlag
= CfRefreshHighLight
;
1997 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2000 // 1. Check whether need to print the arrow up.
2002 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2006 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2007 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2009 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2012 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2014 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2015 TopRow
- SCROLL_ARROW_HEIGHT
,
2018 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2022 // 2.Paint the menu.
2024 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2025 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2026 MenuOption
->Row
= Row
;
2027 MenuOption
->Col
= Col
;
2028 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2029 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2031 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2034 if (MenuOption
->NestInStatement
) {
2035 MenuOption
->Col
+= SUBTITLE_INDENT
;
2039 // Save the highlight menu, will be used in CfRefreshHighLight case.
2041 if (Link
== NewPos
) {
2042 SavedMenuOption
= MenuOption
;
2043 SkipHighLight
= TRUE
;
2046 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2047 DisplayOneMenu (MenuOption
,
2048 LEFT_SKIPPED_COLUMNS
,
2049 gStatementDimensions
.LeftColumn
+ gModalSkipColumn
,
2050 Link
== TopOfScreen
? SkipValue
: 0,
2052 Link
== NewPos
&& IsSelectable(MenuOption
)
2055 DisplayOneMenu (MenuOption
,
2056 LEFT_SKIPPED_COLUMNS
,
2057 gStatementDimensions
.LeftColumn
,
2058 Link
== TopOfScreen
? SkipValue
: 0,
2060 Link
== NewPos
&& IsSelectable(MenuOption
)
2065 // 3. Update the row info which will be used by next menu.
2067 if (Link
== TopOfScreen
) {
2068 Row
+= MenuOption
->Skip
- SkipValue
;
2070 Row
+= MenuOption
->Skip
;
2073 if (Row
> BottomRow
) {
2074 if (!ValueIsScroll (FALSE
, Link
)) {
2078 Row
= BottomRow
+ 1;
2084 // 3. Menus in this form may not cover all form, clean the remain field.
2086 while (Row
<= BottomRow
) {
2087 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2088 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2090 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2095 // 4. Print the down arrow row.
2097 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2098 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * + gModalSkipColumn
);
2100 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2103 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2105 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2106 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2109 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2114 if (IsListEmpty (&gMenuOption
)) {
2115 ControlFlag
= CfReadKey
;
2120 case CfRefreshHighLight
:
2123 // MenuOption: Last menu option that need to remove hilight
2124 // MenuOption is set to NULL in Repaint
2125 // NewPos: Current menu option that need to hilight
2127 ControlFlag
= CfUpdateHelpString
;
2129 if (SkipHighLight
) {
2130 MenuOption
= SavedMenuOption
;
2131 SkipHighLight
= FALSE
;
2132 UpdateHighlightMenuInfo (MenuOption
);
2136 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2141 if (NewPos
== TopOfScreen
) {
2147 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2148 if (MenuOption
!= NULL
) {
2150 // Remove highlight on last Menu Option
2152 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2153 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
2154 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2155 if (OptionString
!= NULL
) {
2156 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
2157 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2159 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2162 Width
= (UINT16
) gOptionBlockWidth
;
2163 OriginalRow
= MenuOption
->Row
;
2166 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2167 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2168 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2171 // If there is more string to process print on the next row and increment the Skip value
2173 if (StrLen (&OptionString
[Index
]) != 0) {
2179 FreePool (OutputString
);
2185 MenuOption
->Row
= OriginalRow
;
2187 FreePool (OptionString
);
2190 if (MenuOption
->GrayOut
) {
2191 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2192 } else if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2193 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2196 OriginalRow
= MenuOption
->Row
;
2197 Width
= GetWidth (MenuOption
->ThisTag
, NULL
);
2200 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2201 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2202 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2205 // If there is more string to process print on the next row and increment the Skip value
2207 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2213 FreePool (OutputString
);
2219 MenuOption
->Row
= OriginalRow
;
2220 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2226 // This is the current selected statement
2228 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2229 Statement
= MenuOption
->ThisTag
;
2231 UpdateHighlightMenuInfo (MenuOption
);
2233 if (!IsSelectable (MenuOption
)) {
2238 // Set reverse attribute
2240 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2241 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2243 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
2244 if (OptionString
!= NULL
) {
2245 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2246 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2248 Width
= (UINT16
) gOptionBlockWidth
;
2250 OriginalRow
= MenuOption
->Row
;
2253 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2254 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2255 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2258 // If there is more string to process print on the next row and increment the Skip value
2260 if (StrLen (&OptionString
[Index
]) != 0) {
2266 FreePool (OutputString
);
2272 MenuOption
->Row
= OriginalRow
;
2274 FreePool (OptionString
);
2277 OriginalRow
= MenuOption
->Row
;
2279 Width
= GetWidth (Statement
, NULL
);
2282 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2283 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2284 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2287 // If there is more string to process print on the next row and increment the Skip value
2289 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2295 FreePool (OutputString
);
2301 MenuOption
->Row
= OriginalRow
;
2307 // Clear reverse attribute
2309 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2313 case CfUpdateHelpString
:
2314 ControlFlag
= CfPrepareToReadKey
;
2315 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2319 if (Repaint
|| NewLine
) {
2321 // Don't print anything if it is a NULL help token
2323 ASSERT(MenuOption
!= NULL
);
2324 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2325 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2326 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2328 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2331 RowCount
= BottomRow
- TopRow
+ 1;
2334 // 1.Calculate how many line the help string need to print.
2336 if (HelpString
!= NULL
) {
2337 FreePool (HelpString
);
2340 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2341 FreePool (StringPtr
);
2343 if (HelpLine
> RowCount
) {
2344 MultiHelpPage
= TRUE
;
2345 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2346 if (HelpHeaderString
!= NULL
) {
2347 FreePool (HelpHeaderString
);
2348 HelpHeaderString
= NULL
;
2350 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2351 FreePool (StringPtr
);
2352 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2353 if (HelpBottomString
!= NULL
) {
2354 FreePool (HelpBottomString
);
2355 HelpBottomString
= NULL
;
2357 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2358 FreePool (StringPtr
);
2360 // Calculate the help page count.
2362 if (HelpLine
> 2 * RowCount
- 2) {
2363 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2364 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
2371 MultiHelpPage
= FALSE
;
2376 // Check whether need to show the 'More(U/u)' at the begin.
2377 // Base on current direct info, here shows aligned to the right side of the column.
2378 // If the direction is multi line and aligned to right side may have problem, so
2379 // add ASSERT code here.
2381 if (HelpPageIndex
> 0) {
2382 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2383 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2384 ASSERT (HelpHeaderLine
== 1);
2385 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2386 PrintStringAtWithWidth (
2387 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2393 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2395 &HelpHeaderString
[Index
* HeaderLineWidth
]
2400 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
2402 // Print the help string info.
2404 if (!MultiHelpPage
) {
2405 for (Index
= 0; Index
< HelpLine
; Index
++) {
2406 PrintStringAtWithWidth (
2407 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2409 &HelpString
[Index
* EachLineWidth
],
2413 for (; Index
< RowCount
; Index
++) {
2414 PrintStringAtWithWidth (
2415 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2421 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2423 if (HelpPageIndex
== 0) {
2424 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
2425 PrintStringAtWithWidth (
2426 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2428 &HelpString
[Index
* EachLineWidth
],
2433 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
2434 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
2435 PrintStringAtWithWidth (
2436 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2437 Index
+ TopRow
+ HelpHeaderLine
,
2438 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
2442 if (HelpPageIndex
== HelpPageCount
- 1) {
2443 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
2444 PrintStringAtWithWidth (
2445 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2446 Index
+ TopRow
+ HelpHeaderLine
,
2451 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2457 // Check whether need to print the 'More(D/d)' at the bottom.
2458 // Base on current direct info, here shows aligned to the right side of the column.
2459 // If the direction is multi line and aligned to right side may have problem, so
2460 // add ASSERT code here.
2462 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
2463 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2464 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
2465 ASSERT (HelpBottomLine
== 1);
2466 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2467 PrintStringAtWithWidth (
2468 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2469 BottomRow
+ Index
- HelpBottomLine
+ 1,
2474 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
2475 BottomRow
+ Index
- HelpBottomLine
+ 1,
2476 &HelpBottomString
[Index
* BottomLineWidth
]
2481 // Reset this flag every time we finish using it.
2487 case CfPrepareToReadKey
:
2488 ControlFlag
= CfReadKey
;
2489 ScreenOperation
= UiNoOperation
;
2493 ControlFlag
= CfScreenOperation
;
2496 // Wait for user's selection
2499 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2500 if (!EFI_ERROR (Status
)) {
2501 EventType
= UIEventKey
;
2506 // If we encounter error, continue to read another key in.
2508 if (Status
!= EFI_NOT_READY
) {
2512 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
2513 if (EventType
== UIEventKey
) {
2514 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2519 if (EventType
== UIEventDriver
) {
2520 gUserInput
->Action
= BROWSER_ACTION_NONE
;
2521 ControlFlag
= CfExit
;
2525 if (EventType
== UIEventTimeOut
) {
2526 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2527 ControlFlag
= CfExit
;
2531 switch (Key
.UnicodeChar
) {
2532 case CHAR_CARRIAGE_RETURN
:
2533 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2534 ControlFlag
= CfReadKey
;
2538 ScreenOperation
= UiSelect
;
2543 // We will push the adjustment of these numeric values directly to the input handler
2544 // NOTE: we won't handle manual input numeric
2549 // If the screen has no menu items, and the user didn't select UiReset
2550 // ignore the selection and go back to reading keys.
2552 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2553 ControlFlag
= CfReadKey
;
2557 ASSERT(MenuOption
!= NULL
);
2558 Statement
= MenuOption
->ThisTag
;
2559 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
2560 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2561 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
2563 if (Key
.UnicodeChar
== '+') {
2564 gDirection
= SCAN_RIGHT
;
2566 gDirection
= SCAN_LEFT
;
2569 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2570 if (OptionString
!= NULL
) {
2571 FreePool (OptionString
);
2573 if (EFI_ERROR (Status
)) {
2575 // Repaint to clear possible error prompt pop-up
2580 ControlFlag
= CfExit
;
2586 ScreenOperation
= UiUp
;
2591 ScreenOperation
= UiDown
;
2595 if(IsListEmpty (&gMenuOption
)) {
2596 ControlFlag
= CfReadKey
;
2600 ASSERT(MenuOption
!= NULL
);
2601 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
2602 ScreenOperation
= UiSelect
;
2608 if (!MultiHelpPage
) {
2609 ControlFlag
= CfReadKey
;
2612 ControlFlag
= CfUpdateHelpString
;
2613 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
2618 if (!MultiHelpPage
) {
2619 ControlFlag
= CfReadKey
;
2622 ControlFlag
= CfUpdateHelpString
;
2623 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
2627 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2628 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2629 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2634 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2636 // ModalForm has no ESC key and Hot Key.
2638 ControlFlag
= CfReadKey
;
2639 } else if (Index
== mScanCodeNumber
) {
2641 // Check whether Key matches the registered hot key.
2644 HotKey
= GetHotKeyFromRegisterList (&Key
);
2645 if (HotKey
!= NULL
) {
2646 ScreenOperation
= UiHotKey
;
2653 case CfScreenOperation
:
2654 if (ScreenOperation
!= UiReset
) {
2656 // If the screen has no menu items, and the user didn't select UiReset
2657 // ignore the selection and go back to reading keys.
2659 if (IsListEmpty (&gMenuOption
)) {
2660 ControlFlag
= CfReadKey
;
2666 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2669 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2670 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2677 ControlFlag
= CfRepaint
;
2679 ASSERT(MenuOption
!= NULL
);
2680 Statement
= MenuOption
->ThisTag
;
2681 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2685 switch (Statement
->OpCode
->OpCode
) {
2686 case EFI_IFR_REF_OP
:
2687 case EFI_IFR_ACTION_OP
:
2688 case EFI_IFR_RESET_BUTTON_OP
:
2689 ControlFlag
= CfExit
;
2694 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2696 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
2697 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2699 if (OptionString
!= NULL
) {
2700 FreePool (OptionString
);
2703 if (EFI_ERROR (Status
)) {
2706 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
2709 ControlFlag
= CfExit
;
2717 // We come here when someone press ESC
2718 // If the policy is not exit front page when user press ESC, process here.
2720 if (!FormExitPolicy()) {
2723 ControlFlag
= CfRepaint
;
2728 // When user press ESC, it will try to show another menu, should clean the gSequence info.
2730 if (gSequence
!= 0) {
2734 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2735 ControlFlag
= CfExit
;
2739 ControlFlag
= CfRepaint
;
2741 gUserInput
->Action
= HotKey
->Action
;
2742 ControlFlag
= CfExit
;
2746 ControlFlag
= CfRepaint
;
2747 ASSERT(MenuOption
!= NULL
);
2748 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2749 if (MenuOption
->Sequence
!= 0) {
2751 // In the middle or tail of the Date/Time op-code set, go left.
2753 ASSERT(NewPos
!= NULL
);
2754 NewPos
= NewPos
->BackLink
;
2760 ControlFlag
= CfRepaint
;
2761 ASSERT(MenuOption
!= NULL
);
2762 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2763 if (MenuOption
->Sequence
!= 2) {
2765 // In the middle or tail of the Date/Time op-code set, go left.
2767 ASSERT(NewPos
!= NULL
);
2768 NewPos
= NewPos
->ForwardLink
;
2774 ControlFlag
= CfRepaint
;
2776 SavedListEntry
= NewPos
;
2778 ASSERT(NewPos
!= NULL
);
2780 // Adjust Date/Time position before we advance forward.
2782 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2783 if (NewPos
->BackLink
!= &gMenuOption
) {
2784 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2785 ASSERT (MenuOption
!= NULL
);
2787 NewPos
= NewPos
->BackLink
;
2789 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2790 if (PreviousMenuOption
->Row
== 0) {
2791 UpdateOptionSkipLines (PreviousMenuOption
);
2793 DistanceValue
= PreviousMenuOption
->Skip
;
2795 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2796 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2798 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2800 if (Difference
< 0) {
2802 // We hit the begining MenuOption that can be focused
2803 // so we simply scroll to the top.
2805 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2806 TopOfScreen
= gMenuOption
.ForwardLink
;
2810 // Scroll up to the last page when we have arrived at top page.
2812 NewPos
= &gMenuOption
;
2813 TopOfScreen
= &gMenuOption
;
2814 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2815 ScreenOperation
= UiPageUp
;
2816 ControlFlag
= CfScreenOperation
;
2819 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2821 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2823 TopOfScreen
= NewPos
;
2826 } else if (!IsSelectable (NextMenuOption
)) {
2828 // Continue to go up until scroll to next page or the selectable option is found.
2830 ScreenOperation
= UiUp
;
2831 ControlFlag
= CfScreenOperation
;
2835 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2837 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2838 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2839 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2840 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2843 // Scroll up to the last page.
2845 NewPos
= &gMenuOption
;
2846 TopOfScreen
= &gMenuOption
;
2847 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2848 ScreenOperation
= UiPageUp
;
2849 ControlFlag
= CfScreenOperation
;
2855 // SkipValue means lines is skipped when show the top menu option.
2857 ControlFlag
= CfRepaint
;
2859 ASSERT(NewPos
!= NULL
);
2861 // Already at the first menu option, Check the skip value.
2863 if (NewPos
->BackLink
== &gMenuOption
) {
2864 if (SkipValue
== 0) {
2879 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
2880 // form of options to be show, so just update the SkipValue to show the next
2881 // parts of options.
2883 if (SkipValue
> (INTN
) (BottomRow
- TopRow
+ 1)) {
2884 SkipValue
-= BottomRow
- TopRow
+ 1;
2890 // First minus the menu of the top screen, it's value is SkipValue.
2892 Index
= (BottomRow
+ 1) - SkipValue
;
2893 while ((Index
> TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2894 Link
= Link
->BackLink
;
2895 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2896 if (PreviousMenuOption
->Row
== 0) {
2897 UpdateOptionSkipLines (PreviousMenuOption
);
2899 if (Index
< PreviousMenuOption
->Skip
) {
2902 Index
= Index
- PreviousMenuOption
->Skip
;
2905 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2907 if (TopOfScreen
== &gMenuOption
) {
2908 TopOfScreen
= gMenuOption
.ForwardLink
;
2909 NewPos
= gMenuOption
.BackLink
;
2910 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2912 } else if (TopOfScreen
!= Link
) {
2915 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2918 // Finally we know that NewPos is the last MenuOption can be focused.
2922 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2925 if (Index
> TopRow
) {
2927 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
2929 SkipValue
= PreviousMenuOption
->Skip
- (Index
- TopRow
);
2930 } else if (Index
== TopRow
) {
2933 SkipValue
= TopRow
- Index
;
2937 // Move to the option in Next page.
2939 if (TopOfScreen
== &gMenuOption
) {
2940 NewPos
= gMenuOption
.BackLink
;
2941 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2944 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2948 // There are more MenuOption needing scrolling up.
2955 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2956 // Don't do this when we are already in the first page.
2958 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2959 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2964 // SkipValue means lines is skipped when show the top menu option.
2966 ControlFlag
= CfRepaint
;
2968 ASSERT (NewPos
!= NULL
);
2969 if (NewPos
->ForwardLink
== &gMenuOption
) {
2978 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2979 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
2981 // Count to the menu option which will show at the top of the next form.
2983 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
2984 Link
= Link
->ForwardLink
;
2985 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2986 Index
= Index
+ NextMenuOption
->Skip
;
2989 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
2991 // Finally we know that NewPos is the last MenuOption can be focused.
2994 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2997 // Calculate the skip line for top of screen menu.
2999 if (Link
== TopOfScreen
) {
3001 // The top of screen menu option occupies the entire form.
3003 SkipValue
+= BottomRow
- TopRow
+ 1;
3005 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3011 // Move to the Next selectable menu.
3013 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
3017 // Save the menu as the next highlight menu.
3022 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3023 // Don't do this when we are already in the last page.
3025 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3026 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3031 // SkipValue means lines is skipped when show the top menu option.
3032 // NewPos points to the menu which is highlighted now.
3034 ControlFlag
= CfRepaint
;
3037 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3038 // to be one that progresses to the next set of op-codes, we need to advance to the last
3039 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3040 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3041 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3042 // the Date/Time op-code.
3044 SavedListEntry
= NewPos
;
3045 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3047 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3048 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3050 NewPos
= NewPos
->ForwardLink
;
3054 // Current menu not at the bottom of the form.
3056 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3058 // Find the next selectable menu.
3060 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3062 // We hit the end of MenuOption that can be focused
3063 // so we simply scroll to the first page.
3065 if (Difference
< 0) {
3067 // Scroll to the first page.
3069 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3070 TopOfScreen
= gMenuOption
.ForwardLink
;
3074 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3076 NewPos
= gMenuOption
.ForwardLink
;
3077 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3081 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3083 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3084 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3088 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3089 if (NextMenuOption
->Row
== 0) {
3090 UpdateOptionSkipLines (NextMenuOption
);
3092 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3094 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3095 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3096 (NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
||
3097 NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3103 // If we are going to scroll, update TopOfScreen
3105 if (Temp
> BottomRow
) {
3108 // Is the current top of screen a zero-advance op-code?
3109 // If so, keep moving forward till we hit a >0 advance op-code
3111 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3114 // If bottom op-code is more than one line or top op-code is more than one line
3116 if ((DistanceValue
> 1) || (SavedMenuOption
->Skip
> 1)) {
3118 // Is the bottom op-code greater than or equal in size to the top op-code?
3120 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3122 // Skip the top op-code
3124 TopOfScreen
= TopOfScreen
->ForwardLink
;
3125 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3127 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3130 // If we have a remainder, skip that many more op-codes until we drain the remainder
3132 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3134 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3136 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3137 TopOfScreen
= TopOfScreen
->ForwardLink
;
3138 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3141 // Since we will act on this op-code in the next routine, and increment the
3142 // SkipValue, set the skips to one less than what is required.
3144 SkipValue
= Difference
- 1;
3147 // Since we will act on this op-code in the next routine, and increment the
3148 // SkipValue, set the skips to one less than what is required.
3150 SkipValue
+= (Temp
- BottomRow
) - 1;
3153 if ((SkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3154 TopOfScreen
= TopOfScreen
->ForwardLink
;
3159 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3160 // Let's set a skip flag to smoothly scroll the top of the screen.
3162 if (SavedMenuOption
->Skip
> 1) {
3163 if (SavedMenuOption
== NextMenuOption
) {
3168 } else if (SavedMenuOption
->Skip
== 1) {
3172 TopOfScreen
= TopOfScreen
->ForwardLink
;
3174 } while (SavedMenuOption
->Skip
== 0);
3177 } else if (!IsSelectable (NextMenuOption
)) {
3179 // Continue to go down until scroll to next page or the selectable option is found.
3181 ScreenOperation
= UiDown
;
3182 ControlFlag
= CfScreenOperation
;
3185 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3187 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3191 // Scroll to the first page.
3193 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3194 TopOfScreen
= gMenuOption
.ForwardLink
;
3199 // Need to remove the current highlight menu.
3200 // MenuOption saved the last highlight menu info.
3202 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3208 // Get the next highlight menu.
3210 NewPos
= gMenuOption
.ForwardLink
;
3211 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3215 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3217 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3218 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3221 case CfUiNoOperation
:
3222 ControlFlag
= CfRepaint
;
3226 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3227 if (HelpString
!= NULL
) {
3228 FreePool (HelpString
);
3230 if (HelpHeaderString
!= NULL
) {
3231 FreePool (HelpHeaderString
);
3233 if (HelpBottomString
!= NULL
) {
3234 FreePool (HelpBottomString
);
3246 Base on the browser status info to show an pop up message.
3250 BrowserStatusProcess (
3257 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3261 if (gFormData
->ErrorString
!= NULL
) {
3262 ErrorInfo
= gFormData
->ErrorString
;
3264 switch (gFormData
->BrowserStatus
) {
3265 case BROWSER_SUBMIT_FAIL
:
3266 ErrorInfo
= gSaveFailed
;
3269 case BROWSER_NO_SUBMIT_IF
:
3270 ErrorInfo
= gNoSubmitIf
;
3273 case BROWSER_FORM_NOT_FOUND
:
3274 ErrorInfo
= gFormNotFound
;
3277 case BROWSER_FORM_SUPPRESS
:
3278 ErrorInfo
= gFormSuppress
;
3281 case BROWSER_PROTOCOL_NOT_FOUND
:
3282 ErrorInfo
= gProtocolNotFound
;
3286 ErrorInfo
= gBrwoserError
;
3292 // Error occur, prompt error message.
3295 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3296 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3300 Display one form, and return user input.
3302 @param FormData Form Data to be shown.
3303 @param UserInputData User input data.
3305 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
3306 2.Error info has show and return.
3307 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
3308 @retval EFI_NOT_FOUND New form data has some error.
3313 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
3314 OUT USER_INPUT
*UserInputData
3319 ASSERT (FormData
!= NULL
);
3320 if (FormData
== NULL
) {
3321 return EFI_INVALID_PARAMETER
;
3324 gUserInput
= UserInputData
;
3325 gFormData
= FormData
;
3328 // Process the status info first.
3330 BrowserStatusProcess();
3331 if (UserInputData
== NULL
) {
3333 // UserInputData == NULL, means only need to print the error info, return here.
3338 ConvertStatementToMenu();
3340 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
3341 if (EFI_ERROR (Status
)) {
3346 // Check whether layout is changed.
3349 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
3350 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
3351 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
3352 mStatementLayoutIsChanged
= TRUE
;
3354 mStatementLayoutIsChanged
= FALSE
;
3357 Status
= UiDisplayMenu(FormData
);
3360 // Backup last form info.
3362 mIsFirstForm
= FALSE
;
3363 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
3364 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
3365 gOldFormEntry
.FormId
= FormData
->FormId
;
3371 Clear Screen to the initial state.
3375 DriverClearDisplayPage (
3379 ClearDisplayPage ();
3380 mIsFirstForm
= TRUE
;
3384 Set Buffer to Value for Size bytes.
3386 @param Buffer Memory to set.
3387 @param Size Number of bytes to set
3388 @param Value Value of the set operation.
3401 while ((Size
--) != 0) {
3407 Initialize Setup Browser driver.
3409 @param ImageHandle The image handle.
3410 @param SystemTable The system table.
3412 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
3413 @return Other value if failed to initialize the Setup Browser module.
3418 InitializeDisplayEngine (
3419 IN EFI_HANDLE ImageHandle
,
3420 IN EFI_SYSTEM_TABLE
*SystemTable
3424 EFI_INPUT_KEY HotKey
;
3425 EFI_STRING NewString
;
3426 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
3429 // Publish our HII data
3431 gHiiHandle
= HiiAddPackages (
3432 &gDisplayEngineGuid
,
3434 DisplayEngineStrings
,
3437 ASSERT (gHiiHandle
!= NULL
);
3440 // Install Form Display protocol
3442 Status
= gBS
->InstallProtocolInterface (
3443 &mPrivateData
.Handle
,
3444 &gEdkiiFormDisplayEngineProtocolGuid
,
3445 EFI_NATIVE_INTERFACE
,
3446 &mPrivateData
.FromDisplayProt
3448 ASSERT_EFI_ERROR (Status
);
3450 InitializeDisplayStrings();
3452 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
3453 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
3456 // Use BrowserEx2 protocol to register HotKey.
3458 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
3459 if (!EFI_ERROR (Status
)) {
3461 // Register the default HotKey F9 and F10 again.
3463 HotKey
.UnicodeChar
= CHAR_NULL
;
3464 HotKey
.ScanCode
= SCAN_F10
;
3465 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
3466 ASSERT (NewString
!= NULL
);
3467 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
3469 HotKey
.ScanCode
= SCAN_F9
;
3470 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
3471 ASSERT (NewString
!= NULL
);
3472 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
3479 This is the default unload handle for display core drivers.
3481 @param[in] ImageHandle The drivers' driver image.
3483 @retval EFI_SUCCESS The image is unloaded.
3484 @retval Others Failed to unload the image.
3489 UnloadDisplayEngine (
3490 IN EFI_HANDLE ImageHandle
3493 HiiRemovePackages(gHiiHandle
);
3495 FreeDisplayStrings ();