2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FormDisplay.h"
19 // Search table for UiDisplayMenu()
21 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
52 UINTN mScanCodeNumber
= ARRAY_SIZE (gScanCodeToOperation
);
54 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
97 EFI_GUID gDisplayEngineGuid
= {
98 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
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
*gReconnectConfirmChanges
;
117 CHAR16
*gReconnectFail
;
118 CHAR16
*gReconnectRequired
;
120 CHAR16
*gFormNotFound
;
122 CHAR16
*gBrowserError
;
124 CHAR16
*gNoSubmitIfFailed
;
125 CHAR16
*gSaveProcess
;
126 CHAR16
*gSaveNoSubmitProcess
;
127 CHAR16
*gDiscardChange
;
128 CHAR16
*gJumpToFormSet
;
130 CHAR16
*gPromptForData
;
131 CHAR16
*gPromptForPassword
;
132 CHAR16
*gPromptForNewPassword
;
133 CHAR16
*gConfirmPassword
;
134 CHAR16
*gConfirmError
;
135 CHAR16
*gPassowordInvalid
;
137 CHAR16
*gEmptyString
;
139 CHAR16
*gOptionMismatch
;
140 CHAR16
*gFormSuppress
;
141 CHAR16
*gProtocolNotFound
;
142 CHAR16
*gConfirmDefaultMsg
;
143 CHAR16
*gConfirmSubmitMsg
;
144 CHAR16
*gConfirmDiscardMsg
;
145 CHAR16
*gConfirmResetMsg
;
146 CHAR16
*gConfirmExitMsg
;
147 CHAR16
*gConfirmSubmitMsg2nd
;
148 CHAR16
*gConfirmDefaultMsg2nd
;
149 CHAR16
*gConfirmResetMsg2nd
;
150 CHAR16
*gConfirmExitMsg2nd
;
152 CHAR16
*gConfirmOptYes
;
153 CHAR16
*gConfirmOptNo
;
154 CHAR16
*gConfirmMsgConnect
;
155 CHAR16
*gConfirmMsgEnd
;
156 CHAR16 gModalSkipColumn
;
157 CHAR16 gPromptBlockWidth
;
158 CHAR16 gOptionBlockWidth
;
159 CHAR16 gHelpBlockWidth
;
160 CHAR16
*mUnknownString
;
162 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
163 FORM_DISPLAY_DRIVER_SIGNATURE
,
167 DriverClearDisplayPage
,
174 Get the string based on the StringId and HII Package List Handle.
176 @param Token The String's ID.
177 @param HiiHandle The package list in the HII database to search for
178 the specified string.
180 @return The output string.
185 IN EFI_STRING_ID Token
,
186 IN EFI_HII_HANDLE HiiHandle
191 String
= HiiGetString (HiiHandle
, Token
, NULL
);
192 if (String
== NULL
) {
193 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
194 ASSERT (String
!= NULL
);
197 return (CHAR16
*) String
;
202 Initialize the HII String Token to the correct values.
206 InitializeDisplayStrings (
210 gReconnectConfirmChanges
= GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES
), gHiiHandle
);
211 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
212 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
213 gNoSubmitIfFailed
= GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED
), gHiiHandle
);
214 gReconnectFail
= GetToken (STRING_TOKEN (RECONNECT_FAILED
), gHiiHandle
);
215 gReconnectRequired
= GetToken (STRING_TOKEN (RECONNECT_REQUIRED
), gHiiHandle
);
216 gChangesOpt
= GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS
), gHiiHandle
);
217 gSaveProcess
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP
), gHiiHandle
);
218 gSaveNoSubmitProcess
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK
), gHiiHandle
);
219 gDiscardChange
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD
), gHiiHandle
);
220 gJumpToFormSet
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP
), gHiiHandle
);
221 gCheckError
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK
), gHiiHandle
);
222 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
223 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
224 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
225 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
226 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
227 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
228 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
229 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
230 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
231 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
232 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
233 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
234 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
235 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
236 gBrowserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
237 gConfirmDefaultMsg
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE
), gHiiHandle
);
238 gConfirmDiscardMsg
= GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE
), gHiiHandle
);
239 gConfirmSubmitMsg
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE
), gHiiHandle
);
240 gConfirmResetMsg
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE
), gHiiHandle
);
241 gConfirmExitMsg
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE
), gHiiHandle
);
242 gConfirmDefaultMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND
), gHiiHandle
);
243 gConfirmSubmitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND
), gHiiHandle
);
244 gConfirmResetMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND
), gHiiHandle
);
245 gConfirmExitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND
), gHiiHandle
);
246 gConfirmOpt
= GetToken (STRING_TOKEN (CONFIRM_OPTION
), gHiiHandle
);
247 gConfirmOptYes
= GetToken (STRING_TOKEN (CONFIRM_OPTION_YES
), gHiiHandle
);
248 gConfirmOptNo
= GetToken (STRING_TOKEN (CONFIRM_OPTION_NO
), gHiiHandle
);
249 gConfirmMsgConnect
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT
), gHiiHandle
);
250 gConfirmMsgEnd
= GetToken (STRING_TOKEN (CONFIRM_OPTION_END
), gHiiHandle
);
254 Free up the resource allocated for all strings required
263 FreePool (mUnknownString
);
264 FreePool (gEmptyString
);
265 FreePool (gSaveFailed
);
266 FreePool (gNoSubmitIfFailed
);
267 FreePool (gReconnectFail
);
268 FreePool (gReconnectRequired
);
269 FreePool (gChangesOpt
);
270 FreePool (gReconnectConfirmChanges
);
271 FreePool (gSaveProcess
);
272 FreePool (gSaveNoSubmitProcess
);
273 FreePool (gDiscardChange
);
274 FreePool (gJumpToFormSet
);
275 FreePool (gCheckError
);
276 FreePool (gPromptForData
);
277 FreePool (gPromptForPassword
);
278 FreePool (gPromptForNewPassword
);
279 FreePool (gConfirmPassword
);
280 FreePool (gConfirmError
);
281 FreePool (gPassowordInvalid
);
282 FreePool (gPressEnter
);
283 FreePool (gMiniString
);
284 FreePool (gOptionMismatch
);
285 FreePool (gFormSuppress
);
286 FreePool (gProtocolNotFound
);
287 FreePool (gBrowserError
);
288 FreePool (gNoSubmitIf
);
289 FreePool (gFormNotFound
);
290 FreePool (gConfirmDefaultMsg
);
291 FreePool (gConfirmSubmitMsg
);
292 FreePool (gConfirmDiscardMsg
);
293 FreePool (gConfirmResetMsg
);
294 FreePool (gConfirmExitMsg
);
295 FreePool (gConfirmDefaultMsg2nd
);
296 FreePool (gConfirmSubmitMsg2nd
);
297 FreePool (gConfirmResetMsg2nd
);
298 FreePool (gConfirmExitMsg2nd
);
299 FreePool (gConfirmOpt
);
300 FreePool (gConfirmOptYes
);
301 FreePool (gConfirmOptNo
);
302 FreePool (gConfirmMsgConnect
);
303 FreePool (gConfirmMsgEnd
);
307 Get prompt string id from the opcode data buffer.
309 @param OpCode The input opcode buffer.
311 @return The prompt string id.
316 IN EFI_IFR_OP_HEADER
*OpCode
319 EFI_IFR_STATEMENT_HEADER
*Header
;
321 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
325 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
327 return Header
->Prompt
;
331 Get the supported width for a particular op-code
333 @param MenuOption The menu option.
334 @param AdjustWidth The width which is saved for the space.
336 @return Returns the number of CHAR16 characters that is support.
341 IN UI_MENU_OPTION
*MenuOption
,
342 OUT UINT16
*AdjustWidth
347 EFI_IFR_TEXT
*TestOp
;
349 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
351 Statement
= MenuOption
->ThisTag
;
354 // For modal form, clean the entire row.
356 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
357 if (AdjustWidth
!= NULL
) {
358 *AdjustWidth
= LEFT_SKIPPED_COLUMNS
;
360 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gModalSkipColumn
+ LEFT_SKIPPED_COLUMNS
));
366 // See if the second text parameter is really NULL
368 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
369 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
370 if (TestOp
->TextTwo
!= 0) {
371 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
372 Size
= StrLen (String
);
377 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
378 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
379 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
380 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
381 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
383 // Allow a wide display if text op-code and no secondary text op-code
385 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
389 // Return the space width.
391 if (AdjustWidth
!= NULL
) {
395 // Keep consistent with current behavior.
397 ReturnWidth
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
399 if (AdjustWidth
!= NULL
) {
403 ReturnWidth
= (UINT16
) (gPromptBlockWidth
- 1);
407 // For nest in statement, should the subtitle indent.
409 if (MenuOption
->NestInStatement
) {
410 ReturnWidth
-= SUBTITLE_INDENT
;
417 Will copy LineWidth amount of a string in the OutputString buffer and return the
418 number of CHAR16 characters that were copied into the OutputString buffer.
419 The output string format is:
420 Glyph Info + String info + '\0'.
422 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
424 @param InputString String description for this option.
425 @param LineWidth Width of the desired string to extract in CHAR16
427 @param GlyphWidth The glyph width of the begin of the char in the string.
428 @param Index Where in InputString to start the copy process
429 @param OutputString Buffer to copy the string into
431 @return Returns the number of CHAR16 characters that were copied into the OutputString
432 buffer, include extra glyph info and '\0' info.
437 IN CHAR16
*InputString
,
439 IN OUT UINT16
*GlyphWidth
,
441 OUT CHAR16
**OutputString
446 UINT16 OriginalGlyphWidth
;
448 UINT16 LastSpaceOffset
;
449 UINT16 LastGlyphWidth
;
451 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
455 if (LineWidth
== 0 || *GlyphWidth
== 0) {
460 // Save original glyph width.
462 OriginalGlyphWidth
= *GlyphWidth
;
463 LastGlyphWidth
= OriginalGlyphWidth
;
468 // 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.
469 // To avoid displaying this empty line in screen, just skip the two CHARs here.
471 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
476 // Fast-forward the string and see if there is a carriage-return in the string
478 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
479 switch (InputString
[*Index
+ StrOffset
]) {
488 case CHAR_CARRIAGE_RETURN
:
495 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
498 // Record the last space info in this line. Will be used in rewind.
500 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
501 LastSpaceOffset
= StrOffset
;
502 LastGlyphWidth
= *GlyphWidth
;
513 // Rewind the string from the maximum size until we see a space to break the line
515 if (GlyphOffset
> LineWidth
) {
517 // Rewind the string to last space char in this line.
519 if (LastSpaceOffset
!= 0) {
520 StrOffset
= LastSpaceOffset
;
521 *GlyphWidth
= LastGlyphWidth
;
524 // Roll back to last char in the line width.
531 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
533 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
538 // Need extra glyph info and '\0' info, so +2.
540 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
541 if (*OutputString
== NULL
) {
546 // Save the glyph info at the begin of the string, will used by Print function.
548 if (OriginalGlyphWidth
== 1) {
549 *(*OutputString
) = NARROW_CHAR
;
551 *(*OutputString
) = WIDE_CHAR
;
554 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
556 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
558 // Skip the space info at the begin of next line.
560 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
561 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
563 // Skip the /n or /n/r info.
565 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
566 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
568 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
570 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
572 // Skip the /r or /r/n info.
574 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
575 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
577 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
580 *Index
= (UINT16
) (*Index
+ StrOffset
);
584 // Include extra glyph info and '\0' info, so +2.
586 return StrOffset
+ 2;
590 Add one menu option by specified description and context.
592 @param Statement Statement of this Menu Option.
593 @param MenuItemCount The index for this Option in the Menu.
594 @param NestIn Whether this statement is nest in another statement.
599 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
600 IN UINT16
*MenuItemCount
,
604 UI_MENU_OPTION
*MenuOption
;
607 UINT16 NumberOfLines
;
611 CHAR16
*OutputString
;
612 EFI_STRING_ID PromptId
;
620 PromptId
= GetPrompt (Statement
->OpCode
);
621 ASSERT (PromptId
!= 0);
623 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
627 for (Index
= 0; Index
< Count
; Index
++) {
628 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
631 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
632 MenuOption
->Description
= GetToken (PromptId
, gFormData
->HiiHandle
);
633 MenuOption
->Handle
= gFormData
->HiiHandle
;
634 MenuOption
->ThisTag
= Statement
;
635 MenuOption
->NestInStatement
= NestIn
;
636 MenuOption
->EntryNumber
= *MenuItemCount
;
638 MenuOption
->Sequence
= Index
;
640 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
641 MenuOption
->GrayOut
= TRUE
;
643 MenuOption
->GrayOut
= FALSE
;
646 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
647 MenuOption
->GrayOut
= TRUE
;
651 // If the form or the question has the lock attribute, deal same as grayout.
653 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
654 MenuOption
->GrayOut
= TRUE
;
657 switch (Statement
->OpCode
->OpCode
) {
658 case EFI_IFR_ORDERED_LIST_OP
:
659 case EFI_IFR_ONE_OF_OP
:
660 case EFI_IFR_NUMERIC_OP
:
661 case EFI_IFR_TIME_OP
:
662 case EFI_IFR_DATE_OP
:
663 case EFI_IFR_CHECKBOX_OP
:
664 case EFI_IFR_PASSWORD_OP
:
665 case EFI_IFR_STRING_OP
:
667 // User could change the value of these items
669 MenuOption
->IsQuestion
= TRUE
;
671 case EFI_IFR_TEXT_OP
:
672 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
674 // Initializing GrayOut option as TRUE for Text setup options
675 // so that those options will be Gray in colour and un selectable.
677 MenuOption
->GrayOut
= TRUE
;
681 MenuOption
->IsQuestion
= FALSE
;
685 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
686 MenuOption
->ReadOnly
= TRUE
;
687 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
688 MenuOption
->GrayOut
= TRUE
;
693 (Statement
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
694 (Statement
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
695 Width
= GetWidth (MenuOption
, NULL
);
696 for (; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
698 // If there is more string to process print on the next row and increment the Skip value
700 if (StrLen (&MenuOption
->Description
[ArrayEntry
]) != 0) {
703 FreePool (OutputString
);
707 // Add three MenuOptions for Date/Time
708 // Data format : [01/02/2004] [11:22:33]
709 // Line number : 0 0 1 0 0 1
716 // Override LineNumber for the MenuOption in Date/Time sequence
718 MenuOption
->Skip
= 1;
720 MenuOption
->Skip
= NumberOfLines
;
723 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
730 Create the menu list base on the form data info.
734 ConvertStatementToMenu (
738 UINT16 MenuItemCount
;
740 LIST_ENTRY
*NestLink
;
741 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
742 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
745 InitializeListHead (&gMenuOption
);
747 Link
= GetFirstNode (&gFormData
->StatementListHead
);
748 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
749 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
750 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
753 // Skip the opcode not recognized by Display core.
755 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
759 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
762 // Check the statement nest in this host statement.
764 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
765 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
766 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
767 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
770 // Skip the opcode not recognized by Display core.
772 if (NestStatement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
776 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
782 Count the storage space of a Unicode string.
784 This function handles the Unicode string with NARROW_CHAR
785 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
786 does not count in the resultant output. If a WIDE_CHAR is
787 hit, then 2 Unicode character will consume an output storage
788 space with size of CHAR16 till a NARROW_CHAR is hit.
790 If String is NULL, then ASSERT ().
792 @param String The input string to be counted.
794 @return Storage space for the input string.
804 UINTN IncrementValue
;
806 ASSERT (String
!= NULL
);
807 if (String
== NULL
) {
817 // Advance to the null-terminator or to the first width directive
820 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
821 Index
++, Count
= Count
+ IncrementValue
826 // We hit the null-terminator, we now have a count
828 if (String
[Index
] == 0) {
832 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
833 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
835 if (String
[Index
] == NARROW_CHAR
) {
837 // Skip to the next character
843 // Skip to the next character
848 } while (String
[Index
] != 0);
851 // Increment by one to include the null-terminator in the size
855 return Count
* sizeof (CHAR16
);
859 Base on the input option string to update the skip value for a menu option.
861 @param MenuOption The MenuOption to be checked.
862 @param OptionString The input option string.
866 UpdateSkipInfoForMenu (
867 IN UI_MENU_OPTION
*MenuOption
,
868 IN CHAR16
*OptionString
874 CHAR16
*OutputString
;
877 Width
= (UINT16
) gOptionBlockWidth
;
881 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
882 if (StrLen (&OptionString
[Index
]) != 0) {
886 FreePool (OutputString
);
889 if ((Row
> MenuOption
->Skip
) &&
890 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
891 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
892 MenuOption
->Skip
= Row
;
897 Update display lines for a Menu Option.
899 @param MenuOption The MenuOption to be checked.
903 UpdateOptionSkipLines (
904 IN UI_MENU_OPTION
*MenuOption
907 CHAR16
*OptionString
;
911 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
912 if (OptionString
!= NULL
) {
913 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
915 FreePool (OptionString
);
918 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
919 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
921 if (OptionString
!= NULL
) {
922 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
924 FreePool (OptionString
);
930 Check whether this Menu Option could be print.
932 Check Prompt string, option string or text two string not NULL.
934 This is an internal function.
936 @param MenuOption The MenuOption to be checked.
938 @retval TRUE This Menu Option is printable.
939 @retval FALSE This Menu Option could not be printable.
944 UI_MENU_OPTION
*MenuOption
948 EFI_STRING OptionString
;
952 if (MenuOption
->Description
[0] != '\0') {
956 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
957 if (EFI_ERROR (Status
)) {
960 if (OptionString
!= NULL
&& OptionString
[0] != '\0') {
961 FreePool (OptionString
);
965 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
966 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
967 ASSERT (OptionString
!= NULL
);
968 if (OptionString
[0] != '\0'){
969 FreePool (OptionString
);
978 Check whether this Menu Option could be highlighted.
980 This is an internal function.
982 @param MenuOption The MenuOption to be checked.
984 @retval TRUE This Menu Option is selectable.
985 @retval FALSE This Menu Option could not be selected.
990 UI_MENU_OPTION
*MenuOption
993 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
994 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
|| !PrintableMenu (MenuOption
)) {
1002 Move to next selectable statement.
1004 This is an internal function.
1006 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1007 @param CurrentPosition Current position.
1008 @param GapToTop Gap position to top or bottom.
1009 @param FindInForm Whether find menu in current form or beyond.
1011 @return The row distance from current MenuOption to next selectable MenuOption.
1013 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
1014 @retval Value Find the selectable menu, maybe the truly selectable, maybe the
1015 first menu showing beyond current form or last menu showing in
1017 The value is the line number between the new selected menu and the
1018 current select menu, not include the new selected menu.
1022 MoveToNextStatement (
1024 IN OUT LIST_ENTRY
**CurrentPosition
,
1026 IN BOOLEAN FindInForm
1031 UI_MENU_OPTION
*NextMenuOption
;
1032 UI_MENU_OPTION
*PreMenuOption
;
1035 Pos
= *CurrentPosition
;
1037 if (Pos
== &gMenuOption
) {
1041 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1044 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1046 // NextMenuOption->Row == 0 means this menu has not calculate
1047 // the NextMenuOption->Skip value yet, just calculate here.
1049 if (NextMenuOption
->Row
== 0) {
1050 UpdateOptionSkipLines (NextMenuOption
);
1053 if (IsSelectable (NextMenuOption
)) {
1058 // In this case, still can't find the selectable menu,
1059 // return the first one beyond the showing form.
1061 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1063 NextMenuOption
= PreMenuOption
;
1068 Distance
+= NextMenuOption
->Skip
;
1071 // Arrive at begin of the menu list.
1073 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1078 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1079 PreMenuOption
= NextMenuOption
;
1082 *CurrentPosition
= &NextMenuOption
->Link
;
1088 Process option string for date/time opcode.
1090 @param MenuOption Menu option point to date/time.
1091 @param OptionString Option string input for process.
1092 @param AddOptCol Whether need to update MenuOption->OptCol.
1096 ProcessStringForDateTime (
1097 UI_MENU_OPTION
*MenuOption
,
1098 CHAR16
*OptionString
,
1104 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1108 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
1110 Statement
= MenuOption
->ThisTag
;
1113 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1114 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
1115 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1116 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
1120 // If leading spaces on OptionString - remove the spaces
1122 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1124 // Base on the blockspace to get the option column info.
1127 MenuOption
->OptCol
++;
1131 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1132 OptionString
[Count
] = OptionString
[Index
];
1135 OptionString
[Count
] = CHAR_NULL
;
1138 // Enable to suppress field in the opcode base on the flag.
1140 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1142 // OptionString format is: <**: **: ****>
1146 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1148 // At this point, only "<**:" in the optionstring.
1149 // Clean the day's ** field, after clean, the format is "< :"
1151 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1152 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1154 // At this point, only "**:" in the optionstring.
1155 // Clean the month's "**" field, after clean, the format is " :"
1157 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1158 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1160 // At this point, only "****>" in the optionstring.
1161 // Clean the year's "****" field, after clean, the format is " >"
1163 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1165 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1167 // OptionString format is: <**: **: **>
1168 // |hour|minute|second|
1171 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1173 // At this point, only "<**:" in the optionstring.
1174 // Clean the hour's ** field, after clean, the format is "< :"
1176 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1177 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1179 // At this point, only "**:" in the optionstring.
1180 // Clean the minute's "**" field, after clean, the format is " :"
1182 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1183 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1185 // At this point, only "**>" in the optionstring.
1186 // Clean the second's "**" field, after clean, the format is " >"
1188 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1195 Adjust Data and Time position accordingly.
1196 Data format : [01/02/2004] [11:22:33]
1197 Line number : 0 0 1 0 0 1
1199 This is an internal function.
1201 @param DirectionUp the up or down direction. False is down. True is
1203 @param CurrentPosition Current position. On return: Point to the last
1204 Option (Year or Second) if up; Point to the first
1205 Option (Month or Hour) if down.
1207 @return Return line number to pad. It is possible that we stand on a zero-advance
1208 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1212 AdjustDateAndTimePosition (
1213 IN BOOLEAN DirectionUp
,
1214 IN OUT LIST_ENTRY
**CurrentPosition
1218 LIST_ENTRY
*NewPosition
;
1219 UI_MENU_OPTION
*MenuOption
;
1220 UINTN PadLineNumber
;
1223 NewPosition
= *CurrentPosition
;
1224 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1226 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1227 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1229 // Calculate the distance from current position to the last Date/Time MenuOption
1232 while (MenuOption
->Skip
== 0) {
1234 NewPosition
= NewPosition
->ForwardLink
;
1235 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1239 NewPosition
= *CurrentPosition
;
1242 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1243 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1244 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1245 // checking can be done.
1247 while (Count
++ < 2) {
1248 NewPosition
= NewPosition
->BackLink
;
1252 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1253 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1254 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1255 // checking can be done.
1257 while (Count
-- > 0) {
1258 NewPosition
= NewPosition
->ForwardLink
;
1262 *CurrentPosition
= NewPosition
;
1265 return PadLineNumber
;
1269 Get step info from numeric opcode.
1271 @param[in] OpCode The input numeric op code.
1273 @return step info for this opcode.
1277 IN EFI_IFR_OP_HEADER
*OpCode
1280 EFI_IFR_NUMERIC
*NumericOp
;
1283 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1285 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1286 case EFI_IFR_NUMERIC_SIZE_1
:
1287 Step
= NumericOp
->data
.u8
.Step
;
1290 case EFI_IFR_NUMERIC_SIZE_2
:
1291 Step
= NumericOp
->data
.u16
.Step
;
1294 case EFI_IFR_NUMERIC_SIZE_4
:
1295 Step
= NumericOp
->data
.u32
.Step
;
1298 case EFI_IFR_NUMERIC_SIZE_8
:
1299 Step
= NumericOp
->data
.u64
.Step
;
1311 Find the registered HotKey based on KeyData.
1313 @param[in] KeyData A pointer to a buffer that describes the keystroke
1314 information for the hot key.
1316 @return The registered HotKey context. If no found, NULL will return.
1319 GetHotKeyFromRegisterList (
1320 IN EFI_INPUT_KEY
*KeyData
1324 BROWSER_HOT_KEY
*HotKey
;
1326 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1327 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1328 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1330 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1334 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1342 Determine if the menu is the last menu that can be selected.
1344 This is an internal function.
1346 @param Direction The scroll direction. False is down. True is up.
1347 @param CurrentPos The current focus.
1349 @return FALSE -- the menu isn't the last menu that can be selected.
1350 @return TRUE -- the menu is the last menu that can be selected.
1355 IN BOOLEAN Direction
,
1356 IN LIST_ENTRY
*CurrentPos
1361 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1363 if (Temp
== &gMenuOption
) {
1371 Wait for a given event to fire, or for an optional timeout to expire.
1373 @param Event The event to wait for
1375 @retval UI_EVENT_TYPE The type of the event which is trigged.
1387 EFI_EVENT TimerEvent
;
1388 EFI_EVENT WaitList
[3];
1389 UI_EVENT_TYPE EventType
;
1392 Timeout
= FormExitTimeout(gFormData
);
1395 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1398 // Set the timer event
1407 WaitList
[0] = Event
;
1409 if (gFormData
->FormRefreshEvent
!= NULL
) {
1410 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1415 WaitList
[EventNum
] = TimerEvent
;
1419 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1420 ASSERT_EFI_ERROR (Status
);
1424 EventType
= UIEventKey
;
1428 if (gFormData
->FormRefreshEvent
!= NULL
) {
1429 EventType
= UIEventDriver
;
1431 ASSERT (Timeout
!= 0 && EventNum
== 2);
1432 EventType
= UIEventTimeOut
;
1437 ASSERT (Index
== 2 && EventNum
== 3);
1438 EventType
= UIEventTimeOut
;
1443 gBS
->CloseEvent (TimerEvent
);
1450 Get question id info from the input opcode header.
1452 @param OpCode The input opcode header pointer.
1454 @retval The question id for this opcode.
1459 IN EFI_IFR_OP_HEADER
*OpCode
1462 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1464 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1468 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1470 return QuestionHeader
->QuestionId
;
1475 Find the top of screen menu base on the current menu.
1477 @param CurPos Current input menu.
1478 @param Rows Totol screen rows.
1479 @param SkipValue SkipValue for this new form.
1481 @retval TopOfScreen Top of screen menu for the new form.
1485 FindTopOfScreenMenu (
1486 IN LIST_ENTRY
*CurPos
,
1488 OUT UINTN
*SkipValue
1492 LIST_ENTRY
*TopOfScreen
;
1493 UI_MENU_OPTION
*PreviousMenuOption
;
1496 PreviousMenuOption
= NULL
;
1498 while (Link
->BackLink
!= &gMenuOption
) {
1499 Link
= Link
->BackLink
;
1500 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1501 if (PreviousMenuOption
->Row
== 0) {
1502 UpdateOptionSkipLines (PreviousMenuOption
);
1504 if (Rows
<= PreviousMenuOption
->Skip
) {
1507 Rows
= Rows
- PreviousMenuOption
->Skip
;
1510 if (Link
->BackLink
== &gMenuOption
) {
1511 TopOfScreen
= gMenuOption
.ForwardLink
;
1512 if (PreviousMenuOption
!= NULL
&& Rows
< PreviousMenuOption
->Skip
) {
1513 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1519 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1526 Get the index info for this opcode.
1528 @param OpCode The input opcode for the statement.
1530 @retval The index of this statement.
1534 GetIndexInfoForOpcode (
1535 IN EFI_IFR_OP_HEADER
*OpCode
1539 UI_MENU_OPTION
*MenuOption
;
1542 NewPos
= gMenuOption
.ForwardLink
;
1545 for (NewPos
= gMenuOption
.ForwardLink
; NewPos
!= &gMenuOption
; NewPos
= NewPos
->ForwardLink
){
1546 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1548 if (CompareMem (MenuOption
->ThisTag
->OpCode
, OpCode
, OpCode
->Length
) == 0) {
1549 if (MenuOption
->ThisTag
->OpCode
== OpCode
) {
1561 Is this the saved highlight statement.
1563 @param HighLightedStatement The input highlight statement.
1565 @retval TRUE This is the highlight statement.
1566 @retval FALSE This is not the highlight statement.
1570 IsSavedHighlightStatement (
1571 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1574 if ((gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
) &&
1575 (gFormData
->FormId
== gHighligthMenuInfo
.FormId
)) {
1576 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1577 return (BOOLEAN
) (gHighligthMenuInfo
.HLTQuestionId
== GetQuestionIdInfo (HighLightedStatement
->OpCode
));
1579 if (CompareMem (gHighligthMenuInfo
.HLTOpCode
, HighLightedStatement
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1580 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(HighLightedStatement
->OpCode
)) {
1593 Is this the highlight menu.
1595 @param MenuOption The input Menu option.
1597 @retval TRUE This is the highlight menu option.
1598 @retval FALSE This is not the highlight menu option.
1602 IsHighLightMenuOption (
1603 IN UI_MENU_OPTION
*MenuOption
1606 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1607 if (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.HLTQuestionId
) {
1608 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1611 if(CompareMem (gHighligthMenuInfo
.HLTOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1612 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1613 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1624 Find the highlight menu.
1626 If the input is NULL, base on the record highlight info in
1627 gHighligthMenuInfo to find the last highlight menu.
1629 @param HighLightedStatement The input highlight statement.
1631 @retval The highlight menu index.
1635 FindHighLightMenuOption (
1636 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1640 UI_MENU_OPTION
*MenuOption
;
1642 NewPos
= gMenuOption
.ForwardLink
;
1643 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1645 if (HighLightedStatement
!= NULL
) {
1646 while (MenuOption
->ThisTag
!= HighLightedStatement
) {
1647 NewPos
= NewPos
->ForwardLink
;
1648 if (NewPos
== &gMenuOption
) {
1650 // Not Found it, break
1654 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1658 // Must find the highlight statement.
1660 ASSERT (NewPos
!= &gMenuOption
);
1663 while (!IsHighLightMenuOption (MenuOption
)) {
1664 NewPos
= NewPos
->ForwardLink
;
1665 if (NewPos
== &gMenuOption
) {
1667 // Not Found it, break
1671 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1675 // Highlight statement has disappear (suppressed/disableed)
1677 if (NewPos
== &gMenuOption
) {
1686 Is this the Top of screen menu.
1688 @param MenuOption The input Menu option.
1690 @retval TRUE This is the Top of screen menu option.
1691 @retval FALSE This is not the Top of screen menu option.
1695 IsTopOfScreeMenuOption (
1696 IN UI_MENU_OPTION
*MenuOption
1699 if (gHighligthMenuInfo
.TOSQuestionId
!= 0) {
1700 return (BOOLEAN
) (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.TOSQuestionId
);
1703 if(CompareMem (gHighligthMenuInfo
.TOSOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.TOSOpCode
->Length
) == 0) {
1704 if (gHighligthMenuInfo
.TOSIndex
== 0 || gHighligthMenuInfo
.TOSIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1715 Find the Top of screen menu.
1717 If the input is NULL, base on the record highlight info in
1718 gHighligthMenuInfo to find the last highlight menu.
1720 @param HighLightedStatement The input highlight statement.
1722 @retval The highlight menu index.
1726 FindTopOfScreenMenuOption (
1731 UI_MENU_OPTION
*MenuOption
;
1733 NewPos
= gMenuOption
.ForwardLink
;
1734 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1736 while (!IsTopOfScreeMenuOption(MenuOption
)) {
1737 NewPos
= NewPos
->ForwardLink
;
1738 if (NewPos
== &gMenuOption
) {
1740 // Not Found it, break
1744 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1748 // Last time top of screen menu has disappeared.
1750 if (NewPos
== &gMenuOption
) {
1758 Find the first menu which will be show at the top.
1760 @param FormData The data info for this form.
1761 @param TopOfScreen The link_entry pointer to top menu.
1762 @param HighlightMenu The menu which will be highlight.
1763 @param SkipValue The skip value for the top menu.
1768 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1769 OUT LIST_ENTRY
**TopOfScreen
,
1770 OUT LIST_ENTRY
**HighlightMenu
,
1771 OUT UINTN
*SkipValue
1776 UI_MENU_OPTION
*MenuOption
;
1779 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1780 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1782 // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
1783 // and the other is exit current form and enter last form, it can be covered by the else case.
1785 if (gMisMatch
&& gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
&& gFormData
->FormId
== gHighligthMenuInfo
.FormId
) {
1787 // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
1788 // base on the record highlight info to find the highlight menu.
1791 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1792 if (*HighlightMenu
!= NULL
) {
1794 // Update skip info for this highlight menu.
1796 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1797 UpdateOptionSkipLines (MenuOption
);
1800 // Found the last time highlight menu.
1802 *TopOfScreen
= FindTopOfScreenMenuOption();
1803 if (*TopOfScreen
!= NULL
) {
1805 // Found the last time selectable top of screen menu.
1807 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1808 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1809 UpdateOptionSkipLines (MenuOption
);
1811 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1814 // Not found last time top of screen menu, so base on current highlight menu
1815 // to find the new top of screen menu.
1816 // Make the current highlight menu at the bottom of the form to calculate the
1817 // top of screen menu.
1819 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1820 *TopOfScreen
= *HighlightMenu
;
1823 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1826 *SkipValue
= TmpValue
;
1830 // Last time highlight menu has disappear, find the first highlightable menu as the default one.
1832 *HighlightMenu
= gMenuOption
.ForwardLink
;
1833 if (!IsListEmpty (&gMenuOption
)) {
1834 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1836 *TopOfScreen
= gMenuOption
.ForwardLink
;
1840 } else if (FormData
->HighLightedStatement
!= NULL
) {
1841 if (IsSavedHighlightStatement (FormData
->HighLightedStatement
)) {
1843 // Input highlight menu is same as last time highlight menu.
1844 // Base on last time highlight menu to set the top of screen menu and highlight menu.
1846 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1847 ASSERT (*HighlightMenu
!= NULL
);
1850 // Update skip info for this highlight menu.
1852 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1853 UpdateOptionSkipLines (MenuOption
);
1855 *TopOfScreen
= FindTopOfScreenMenuOption();
1856 if (*TopOfScreen
== NULL
) {
1858 // Not found last time top of screen menu, so base on current highlight menu
1859 // to find the new top of screen menu.
1860 // Make the current highlight menu at the bottom of the form to calculate the
1861 // top of screen menu.
1863 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1864 *TopOfScreen
= *HighlightMenu
;
1867 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1870 *SkipValue
= TmpValue
;
1872 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1873 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1874 UpdateOptionSkipLines (MenuOption
);
1876 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1878 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1881 // Input highlight menu is not save as last time highlight menu.
1883 *HighlightMenu
= FindHighLightMenuOption(FormData
->HighLightedStatement
);
1884 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1885 UpdateOptionSkipLines (MenuOption
);
1888 // Make the current highlight menu at the bottom of the form to calculate the
1889 // top of screen menu.
1891 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1892 *TopOfScreen
= *HighlightMenu
;
1895 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1898 *SkipValue
= TmpValue
;
1900 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1903 // If not has input highlight statement, just return the first one in this form.
1905 *TopOfScreen
= gMenuOption
.ForwardLink
;
1906 *HighlightMenu
= gMenuOption
.ForwardLink
;
1907 if (!IsListEmpty (&gMenuOption
)) {
1908 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1916 // First enter to show the menu, update highlight info.
1918 UpdateHighlightMenuInfo (*HighlightMenu
, *TopOfScreen
, *SkipValue
);
1922 Record the highlight menu and top of screen menu info.
1924 @param Highlight The menu opton which is highlight.
1925 @param TopOfScreen The menu opton which is at the top of the form.
1926 @param SkipValue The skip line info for the top of screen menu.
1930 UpdateHighlightMenuInfo (
1931 IN LIST_ENTRY
*Highlight
,
1932 IN LIST_ENTRY
*TopOfScreen
,
1936 UI_MENU_OPTION
*MenuOption
;
1937 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1939 gHighligthMenuInfo
.HiiHandle
= gFormData
->HiiHandle
;
1940 gHighligthMenuInfo
.FormId
= gFormData
->FormId
;
1941 gHighligthMenuInfo
.SkipValue
= (UINT16
)SkipValue
;
1943 if (!IsListEmpty (&gMenuOption
)) {
1944 MenuOption
= MENU_OPTION_FROM_LINK (Highlight
);
1945 Statement
= MenuOption
->ThisTag
;
1947 gUserInput
->SelectedStatement
= Statement
;
1949 gHighligthMenuInfo
.HLTSequence
= MenuOption
->Sequence
;
1950 gHighligthMenuInfo
.HLTQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1951 if (gHighligthMenuInfo
.HLTQuestionId
== 0) {
1953 // if question id == 0, save the opcode buffer..
1955 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
1956 FreePool (gHighligthMenuInfo
.HLTOpCode
);
1958 gHighligthMenuInfo
.HLTOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
1959 ASSERT (gHighligthMenuInfo
.HLTOpCode
!= NULL
);
1961 gHighligthMenuInfo
.HLTIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
1964 MenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
1965 Statement
= MenuOption
->ThisTag
;
1967 gHighligthMenuInfo
.TOSQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1968 if (gHighligthMenuInfo
.TOSQuestionId
== 0) {
1970 // if question id == 0, save the opcode buffer..
1972 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
1973 FreePool (gHighligthMenuInfo
.TOSOpCode
);
1975 gHighligthMenuInfo
.TOSOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
1976 ASSERT (gHighligthMenuInfo
.TOSOpCode
!= NULL
);
1978 gHighligthMenuInfo
.TOSIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
1981 gUserInput
->SelectedStatement
= NULL
;
1983 gHighligthMenuInfo
.HLTSequence
= 0;
1984 gHighligthMenuInfo
.HLTQuestionId
= 0;
1985 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
1986 FreePool (gHighligthMenuInfo
.HLTOpCode
);
1988 gHighligthMenuInfo
.HLTOpCode
= NULL
;
1989 gHighligthMenuInfo
.HLTIndex
= 0;
1991 gHighligthMenuInfo
.TOSQuestionId
= 0;
1992 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
1993 FreePool (gHighligthMenuInfo
.TOSOpCode
);
1995 gHighligthMenuInfo
.TOSOpCode
= NULL
;
1996 gHighligthMenuInfo
.TOSIndex
= 0;
2001 Update attribut for this menu.
2003 @param MenuOption The menu opton which this attribut used to.
2004 @param Highlight Whether this menu will be highlight.
2008 SetDisplayAttribute (
2009 IN UI_MENU_OPTION
*MenuOption
,
2010 IN BOOLEAN Highlight
2013 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2015 Statement
= MenuOption
->ThisTag
;
2018 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2022 if (MenuOption
->GrayOut
) {
2023 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2025 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2026 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2028 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2034 Print string for this menu option.
2036 @param MenuOption The menu opton which this attribut used to.
2037 @param Col The column that this string will be print at.
2038 @param Row The row that this string will be print at.
2039 @param String The string which need to print.
2040 @param Width The width need to print, if string is less than the
2041 width, the block space will be used.
2042 @param Highlight Whether this menu will be highlight.
2047 IN UI_MENU_OPTION
*MenuOption
,
2052 IN BOOLEAN Highlight
2058 // Print string with normal color.
2061 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
2066 // Print the highlight menu string.
2067 // First print the highlight string.
2069 SetDisplayAttribute(MenuOption
, TRUE
);
2070 Length
= PrintStringAt (Col
, Row
, String
);
2073 // Second, clean the empty after the string.
2075 SetDisplayAttribute(MenuOption
, FALSE
);
2076 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
2080 Check whether this menu can has option string.
2082 @param MenuOption The menu opton which this attribut used to.
2084 @retval TRUE This menu option can have option string.
2085 @retval FALSE This menu option can't have option string.
2090 IN UI_MENU_OPTION
*MenuOption
2093 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2096 EFI_IFR_TEXT
*TestOp
;
2099 Statement
= MenuOption
->ThisTag
;
2102 // See if the second text parameter is really NULL
2104 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2105 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
2106 if (TestOp
->TextTwo
!= 0) {
2107 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
2108 Size
= StrLen (String
);
2113 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
2114 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
2115 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
2116 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
2117 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
2119 // Allow a wide display if text op-code and no secondary text op-code
2121 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
2131 Double confirm with user about the action.
2133 @param Action The user input action.
2135 @retval TRUE User confirm with the input or not need user confirm.
2136 @retval FALSE User want ignore this input.
2153 CatLen
= StrLen (gConfirmMsgConnect
);
2156 // Below action need extra popup dialog to confirm.
2158 CheckFlags
= BROWSER_ACTION_DISCARD
|
2159 BROWSER_ACTION_DEFAULT
|
2160 BROWSER_ACTION_SUBMIT
|
2161 BROWSER_ACTION_RESET
|
2162 BROWSER_ACTION_EXIT
;
2165 // Not need to confirm with user, just return TRUE.
2167 if ((Action
& CheckFlags
) == 0) {
2171 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2172 CfmStrLen
+= StrLen (gConfirmDiscardMsg
);
2175 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2176 if (CfmStrLen
!= 0) {
2177 CfmStrLen
+= CatLen
;
2180 CfmStrLen
+= StrLen (gConfirmDefaultMsg
);
2183 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2184 if (CfmStrLen
!= 0) {
2185 CfmStrLen
+= CatLen
;
2188 CfmStrLen
+= StrLen (gConfirmSubmitMsg
);
2191 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2192 if (CfmStrLen
!= 0) {
2193 CfmStrLen
+= CatLen
;
2196 CfmStrLen
+= StrLen (gConfirmResetMsg
);
2199 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2200 if (CfmStrLen
!= 0) {
2201 CfmStrLen
+= CatLen
;
2204 CfmStrLen
+= StrLen (gConfirmExitMsg
);
2208 // Allocate buffer to save the string.
2209 // String + "?" + "\0"
2211 MaxLen
= CfmStrLen
+ 1 + 1;
2212 CfmStr
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
2213 ASSERT (CfmStr
!= NULL
);
2215 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2216 StrCpyS (CfmStr
, MaxLen
, gConfirmDiscardMsg
);
2219 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2220 if (CfmStr
[0] != 0) {
2221 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2222 StrCatS (CfmStr
, MaxLen
, gConfirmDefaultMsg2nd
);
2224 StrCpyS (CfmStr
, MaxLen
, gConfirmDefaultMsg
);
2228 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2229 if (CfmStr
[0] != 0) {
2230 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2231 StrCatS (CfmStr
, MaxLen
, gConfirmSubmitMsg2nd
);
2233 StrCpyS (CfmStr
, MaxLen
, gConfirmSubmitMsg
);
2237 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2238 if (CfmStr
[0] != 0) {
2239 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2240 StrCatS (CfmStr
, MaxLen
, gConfirmResetMsg2nd
);
2242 StrCpyS (CfmStr
, MaxLen
, gConfirmResetMsg
);
2246 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2247 if (CfmStr
[0] != 0) {
2248 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2249 StrCatS (CfmStr
, MaxLen
, gConfirmExitMsg2nd
);
2251 StrCpyS (CfmStr
, MaxLen
, gConfirmExitMsg
);
2255 StrCatS (CfmStr
, MaxLen
, gConfirmMsgEnd
);
2258 CreateDialog (&Key
, gEmptyString
, CfmStr
, gConfirmOpt
, gEmptyString
, NULL
);
2259 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2260 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptNo
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2261 (Key
.ScanCode
!= SCAN_ESC
));
2263 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) {
2275 Print string for this menu option.
2277 @param MenuOption The menu opton which this attribut used to.
2278 @param SkipWidth The skip width between the left to the start of the prompt.
2279 @param BeginCol The begin column for one menu.
2280 @param SkipLine The skip line for this menu.
2281 @param BottomRow The bottom row for this form.
2282 @param Highlight Whether this menu will be highlight.
2283 @param UpdateCol Whether need to update the column info for Date/Time.
2285 @retval EFI_SUCESSS Process the user selection success.
2290 IN UI_MENU_OPTION
*MenuOption
,
2295 IN BOOLEAN Highlight
,
2296 IN BOOLEAN UpdateCol
2299 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2304 CHAR16
*OptionString
;
2305 CHAR16
*OutputString
;
2312 BOOLEAN IsProcessingFirstRow
;
2314 UINTN PromptLineNum
;
2315 UINTN OptionLineNum
;
2319 Statement
= MenuOption
->ThisTag
;
2327 IsProcessingFirstRow
= TRUE
;
2330 // Set default color.
2332 SetDisplayAttribute (MenuOption
, FALSE
);
2335 // 1. Paint the option string.
2337 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
2338 if (EFI_ERROR (Status
)) {
2342 if (OptionString
!= NULL
) {
2343 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2345 // Adjust option string for date/time opcode.
2347 ProcessStringForDateTime(MenuOption
, OptionString
, UpdateCol
);
2350 Width
= (UINT16
) gOptionBlockWidth
- 1;
2351 Row
= MenuOption
->Row
;
2355 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2356 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
2357 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2359 // For date/time question, it has three menu options for this qustion.
2360 // The first/second menu options with the skip value is 0. the last one
2361 // with skip value is 1.
2363 if (MenuOption
->Skip
!= 0) {
2365 // For date/ time, print the last past (year for date and second for time)
2366 // - 7 means skip [##/##/ for date and [##:##: for time.
2368 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
2371 // For date/ time, print the first and second past (year for date and second for time)
2372 // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
2373 // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
2374 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
) - 1, Highlight
);
2377 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2383 // If there is more string to process print on the next row and increment the Skip value
2385 if (StrLen (&OptionString
[Index
]) != 0) {
2389 // Since the Number of lines for this menu entry may or may not be reflected accurately
2390 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2391 // some testing to ensure we are keeping this in-sync.
2393 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2395 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2401 FreePool (OutputString
);
2409 FreePool (OptionString
);
2413 // 2. Paint the description.
2415 PromptWidth
= GetWidth (MenuOption
, &AdjustValue
);
2416 Row
= MenuOption
->Row
;
2420 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
2421 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
2424 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2425 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2427 // 1.Clean the start LEFT_SKIPPED_COLUMNS
2429 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
2431 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2 && IsProcessingFirstRow
) {
2433 // Print Arrow for Goto button.
2436 MenuOption
->Col
- 2,
2438 GEOMETRICSHAPE_RIGHT_TRIANGLE
2440 IsProcessingFirstRow
= FALSE
;
2442 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
2446 // If there is more string to process print on the next row and increment the Skip value
2448 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2454 FreePool (OutputString
);
2465 // 3. If this is a text op with secondary text information
2467 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
2468 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
2470 Width
= (UINT16
) gOptionBlockWidth
- 1;
2471 Row
= MenuOption
->Row
;
2475 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2476 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
2477 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2481 // If there is more string to process print on the next row and increment the Skip value
2483 if (StrLen (&StringPtr
[Index
]) != 0) {
2487 // If the rows for text two is greater than or equal to the skip value, increase the skip value
2489 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2495 FreePool (OutputString
);
2501 FreePool (StringPtr
);
2505 // 4.Line number for Option string and prompt string are not equal.
2506 // Clean the column whose line number is less.
2508 if (HasOptionString(MenuOption
) && (OptionLineNum
!= PromptLineNum
)) {
2509 Col
= OptionLineNum
< PromptLineNum
? MenuOption
->OptCol
: BeginCol
;
2510 Row
= (OptionLineNum
< PromptLineNum
? OptionLineNum
: PromptLineNum
) + MenuOption
->Row
;
2511 Width
= (UINT16
) (OptionLineNum
< PromptLineNum
? gOptionBlockWidth
: PromptWidth
+ AdjustValue
+ SkipWidth
);
2512 MaxRow
= (OptionLineNum
< PromptLineNum
? PromptLineNum
: OptionLineNum
) + MenuOption
->Row
- 1;
2514 while (Row
<= MaxRow
) {
2515 DisplayMenuString (MenuOption
, Col
, Row
++, L
"", Width
, FALSE
);
2523 Display menu and wait for user to select one menu option, then return it.
2524 If AutoBoot is enabled, then if user doesn't select any option,
2525 after period of time, it will automatically return the first menu option.
2527 @param FormData The current form data info.
2529 @retval EFI_SUCESSS Process the user selection success.
2530 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
2535 IN FORM_DISPLAY_ENGINE_FORM
*FormData
2540 UINTN DistanceValue
;
2549 CHAR16
*StringRightPtr
;
2550 CHAR16
*StringErrorPtr
;
2551 CHAR16
*OptionString
;
2553 CHAR16
*HelpHeaderString
;
2554 CHAR16
*HelpBottomString
;
2563 LIST_ENTRY
*TopOfScreen
;
2564 LIST_ENTRY
*SavedListEntry
;
2565 UI_MENU_OPTION
*MenuOption
;
2566 UI_MENU_OPTION
*NextMenuOption
;
2567 UI_MENU_OPTION
*SavedMenuOption
;
2568 UI_CONTROL_FLAG ControlFlag
;
2569 UI_SCREEN_OPERATION ScreenOperation
;
2570 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2571 BROWSER_HOT_KEY
*HotKey
;
2572 UINTN HelpPageIndex
;
2573 UINTN HelpPageCount
;
2576 UINTN HelpHeaderLine
;
2577 UINTN HelpBottomLine
;
2578 BOOLEAN MultiHelpPage
;
2579 UINT16 EachLineWidth
;
2580 UINT16 HeaderLineWidth
;
2581 UINT16 BottomLineWidth
;
2582 EFI_STRING_ID HelpInfo
;
2583 UI_EVENT_TYPE EventType
;
2584 BOOLEAN SkipHighLight
;
2585 EFI_HII_VALUE
*StatementValue
;
2587 EventType
= UIEventNone
;
2588 Status
= EFI_SUCCESS
;
2590 HelpHeaderString
= NULL
;
2591 HelpBottomString
= NULL
;
2592 OptionString
= NULL
;
2593 ScreenOperation
= UiNoOperation
;
2601 MultiHelpPage
= FALSE
;
2603 HeaderLineWidth
= 0;
2604 BottomLineWidth
= 0;
2608 SkipHighLight
= FALSE
;
2610 NextMenuOption
= NULL
;
2611 SavedMenuOption
= NULL
;
2615 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
2617 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2619 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
2620 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
2623 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2624 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
2626 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2629 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
2630 if (!IsListEmpty (&gMenuOption
)) {
2631 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2632 gUserInput
->SelectedStatement
= NextMenuOption
->ThisTag
;
2635 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2637 ControlFlag
= CfInitialization
;
2639 switch (ControlFlag
) {
2640 case CfInitialization
:
2641 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
2642 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
2644 // Clear Statement range if different formset is painted.
2647 gStatementDimensions
.LeftColumn
,
2648 gStatementDimensions
.RightColumn
,
2649 TopRow
- SCROLL_ARROW_HEIGHT
,
2650 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2651 GetFieldTextColor ()
2655 ControlFlag
= CfRepaint
;
2659 ControlFlag
= CfRefreshHighLight
;
2669 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2672 // 1. Check whether need to print the arrow up.
2674 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2678 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2679 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2681 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2684 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2686 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2687 TopRow
- SCROLL_ARROW_HEIGHT
,
2690 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2694 // 2.Paint the menu.
2696 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2697 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2698 MenuOption
->Row
= Row
;
2699 MenuOption
->Col
= Col
;
2700 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2701 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2703 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2706 if (MenuOption
->NestInStatement
) {
2707 MenuOption
->Col
+= SUBTITLE_INDENT
;
2711 // Save the highlight menu, will be used in CfRefreshHighLight case.
2713 if (Link
== NewPos
) {
2714 SavedMenuOption
= MenuOption
;
2715 SkipHighLight
= TRUE
;
2718 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2719 Status
= DisplayOneMenu (MenuOption
,
2720 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2721 gStatementDimensions
.LeftColumn
+ gModalSkipColumn
,
2722 Link
== TopOfScreen
? SkipValue
: 0,
2724 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2728 Status
= DisplayOneMenu (MenuOption
,
2729 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2730 gStatementDimensions
.LeftColumn
,
2731 Link
== TopOfScreen
? SkipValue
: 0,
2733 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2738 if (EFI_ERROR (Status
)) {
2746 // 3. Update the row info which will be used by next menu.
2748 if (Link
== TopOfScreen
) {
2749 Row
+= MenuOption
->Skip
- SkipValue
;
2751 Row
+= MenuOption
->Skip
;
2754 if (Row
> BottomRow
) {
2755 if (!ValueIsScroll (FALSE
, Link
)) {
2759 Row
= BottomRow
+ 1;
2765 // 3. Menus in this form may not cover all form, clean the remain field.
2767 while (Row
<= BottomRow
) {
2768 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2769 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2771 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2776 // 4. Print the down arrow row.
2778 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2779 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * + gModalSkipColumn
);
2781 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2784 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2786 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2787 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2790 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2797 case CfRefreshHighLight
:
2800 // MenuOption: Last menu option that need to remove hilight
2801 // MenuOption is set to NULL in Repaint
2802 // NewPos: Current menu option that need to hilight
2804 ControlFlag
= CfUpdateHelpString
;
2806 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
2808 if (SkipHighLight
) {
2809 SkipHighLight
= FALSE
;
2810 MenuOption
= SavedMenuOption
;
2811 RefreshKeyHelp(gFormData
, SavedMenuOption
->ThisTag
, FALSE
);
2815 if (IsListEmpty (&gMenuOption
)) {
2817 // No menu option, just update the hotkey filed.
2819 RefreshKeyHelp(gFormData
, NULL
, FALSE
);
2823 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2828 if (NewPos
== TopOfScreen
) {
2834 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2835 if (MenuOption
!= NULL
) {
2837 // Remove the old highlight menu.
2839 Status
= DisplayOneMenu (MenuOption
,
2840 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2841 gStatementDimensions
.LeftColumn
,
2850 // This is the current selected statement
2852 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2853 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2855 if (!IsSelectable (MenuOption
)) {
2859 Status
= DisplayOneMenu (MenuOption
,
2860 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2861 gStatementDimensions
.LeftColumn
,
2870 case CfUpdateHelpString
:
2871 ControlFlag
= CfPrepareToReadKey
;
2872 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2877 // NewLine means only update highlight menu (remove old highlight and highlith
2878 // the new one), not need to full repain the form.
2880 if (Repaint
|| NewLine
) {
2881 if (IsListEmpty (&gMenuOption
)) {
2883 // Don't print anything if no mwnu option.
2885 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2888 // Don't print anything if it is a NULL help token
2890 ASSERT(MenuOption
!= NULL
);
2891 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2892 Statement
= MenuOption
->ThisTag
;
2893 StatementValue
= &Statement
->CurrentValue
;
2894 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2895 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
&& StatementValue
->Value
.date
.Month
== 0xff)||(Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
&& StatementValue
->Value
.time
.Hour
== 0xff)){
2896 StringPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2898 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2901 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
&& StatementValue
->Value
.date
.Month
== 0xff)||(Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
&& StatementValue
->Value
.time
.Hour
== 0xff)){
2902 StringRightPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2903 StringErrorPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2904 StringPtr
= AllocateZeroPool ((StrLen (StringRightPtr
) + StrLen (StringErrorPtr
)+ 1 ) * sizeof (CHAR16
));
2905 StrCpyS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringRightPtr
);
2906 StrCatS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringErrorPtr
);
2907 FreePool (StringRightPtr
);
2908 FreePool (StringErrorPtr
);
2910 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2915 RowCount
= BottomRow
- TopRow
+ 1;
2918 // 1.Calculate how many line the help string need to print.
2920 if (HelpString
!= NULL
) {
2921 FreePool (HelpString
);
2924 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2925 FreePool (StringPtr
);
2927 if (HelpLine
> RowCount
) {
2928 MultiHelpPage
= TRUE
;
2929 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2930 if (HelpHeaderString
!= NULL
) {
2931 FreePool (HelpHeaderString
);
2932 HelpHeaderString
= NULL
;
2934 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2935 FreePool (StringPtr
);
2936 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2937 if (HelpBottomString
!= NULL
) {
2938 FreePool (HelpBottomString
);
2939 HelpBottomString
= NULL
;
2941 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2942 FreePool (StringPtr
);
2944 // Calculate the help page count.
2946 if (HelpLine
> 2 * RowCount
- 2) {
2947 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2948 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) != 0) {
2955 MultiHelpPage
= FALSE
;
2960 // Check whether need to show the 'More(U/u)' at the begin.
2961 // Base on current direct info, here shows aligned to the right side of the column.
2962 // If the direction is multi line and aligned to right side may have problem, so
2963 // add ASSERT code here.
2965 if (HelpPageIndex
> 0) {
2966 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2967 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2968 ASSERT (HelpHeaderLine
== 1);
2969 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2970 PrintStringAtWithWidth (
2971 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2977 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2979 &HelpHeaderString
[Index
* HeaderLineWidth
]
2984 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
2986 // Print the help string info.
2988 if (!MultiHelpPage
) {
2989 for (Index
= 0; Index
< HelpLine
; Index
++) {
2990 PrintStringAtWithWidth (
2991 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2993 &HelpString
[Index
* EachLineWidth
],
2997 for (; Index
< RowCount
; Index
++) {
2998 PrintStringAtWithWidth (
2999 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3005 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3007 if (HelpPageIndex
== 0) {
3008 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
3009 PrintStringAtWithWidth (
3010 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3012 &HelpString
[Index
* EachLineWidth
],
3017 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
3018 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
3019 PrintStringAtWithWidth (
3020 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3021 Index
+ TopRow
+ HelpHeaderLine
,
3022 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
3026 if (HelpPageIndex
== HelpPageCount
- 1) {
3027 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
3028 PrintStringAtWithWidth (
3029 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3030 Index
+ TopRow
+ HelpHeaderLine
,
3035 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3041 // Check whether need to print the 'More(D/d)' at the bottom.
3042 // Base on current direct info, here shows aligned to the right side of the column.
3043 // If the direction is multi line and aligned to right side may have problem, so
3044 // add ASSERT code here.
3046 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
3047 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3048 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
3049 ASSERT (HelpBottomLine
== 1);
3050 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
3051 PrintStringAtWithWidth (
3052 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3053 BottomRow
+ Index
- HelpBottomLine
+ 1,
3058 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
3059 BottomRow
+ Index
- HelpBottomLine
+ 1,
3060 &HelpBottomString
[Index
* BottomLineWidth
]
3065 // Reset this flag every time we finish using it.
3071 case CfPrepareToReadKey
:
3072 ControlFlag
= CfReadKey
;
3073 ScreenOperation
= UiNoOperation
;
3077 ControlFlag
= CfScreenOperation
;
3080 // Wait for user's selection
3083 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3084 if (!EFI_ERROR (Status
)) {
3085 EventType
= UIEventKey
;
3090 // If we encounter error, continue to read another key in.
3092 if (Status
!= EFI_NOT_READY
) {
3096 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
3097 if (EventType
== UIEventKey
) {
3098 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3103 if (EventType
== UIEventDriver
) {
3105 gUserInput
->Action
= BROWSER_ACTION_NONE
;
3106 ControlFlag
= CfExit
;
3110 if (EventType
== UIEventTimeOut
) {
3111 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3112 ControlFlag
= CfExit
;
3116 switch (Key
.UnicodeChar
) {
3117 case CHAR_CARRIAGE_RETURN
:
3118 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3119 ControlFlag
= CfReadKey
;
3123 ScreenOperation
= UiSelect
;
3128 // We will push the adjustment of these numeric values directly to the input handler
3129 // NOTE: we won't handle manual input numeric
3134 // If the screen has no menu items, and the user didn't select UiReset
3135 // ignore the selection and go back to reading keys.
3137 ASSERT(MenuOption
!= NULL
);
3138 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3139 ControlFlag
= CfReadKey
;
3143 Statement
= MenuOption
->ThisTag
;
3144 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
3145 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3146 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
3148 if (Key
.UnicodeChar
== '+') {
3149 gDirection
= SCAN_RIGHT
;
3151 gDirection
= SCAN_LEFT
;
3154 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3155 if (OptionString
!= NULL
) {
3156 FreePool (OptionString
);
3158 if (EFI_ERROR (Status
)) {
3160 // Repaint to clear possible error prompt pop-up
3165 ControlFlag
= CfExit
;
3171 ScreenOperation
= UiUp
;
3176 ScreenOperation
= UiDown
;
3180 if(IsListEmpty (&gMenuOption
)) {
3181 ControlFlag
= CfReadKey
;
3185 ASSERT(MenuOption
!= NULL
);
3186 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3187 ScreenOperation
= UiSelect
;
3193 if (!MultiHelpPage
) {
3194 ControlFlag
= CfReadKey
;
3197 ControlFlag
= CfUpdateHelpString
;
3198 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3203 if (!MultiHelpPage
) {
3204 ControlFlag
= CfReadKey
;
3207 ControlFlag
= CfUpdateHelpString
;
3208 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3212 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3213 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3214 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3219 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3221 // ModalForm has no ESC key and Hot Key.
3223 ControlFlag
= CfReadKey
;
3224 } else if (Index
== mScanCodeNumber
) {
3226 // Check whether Key matches the registered hot key.
3229 HotKey
= GetHotKeyFromRegisterList (&Key
);
3230 if (HotKey
!= NULL
) {
3231 ScreenOperation
= UiHotKey
;
3238 case CfScreenOperation
:
3239 if ((ScreenOperation
!= UiReset
) && (ScreenOperation
!= UiHotKey
)) {
3241 // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
3242 // ignore the selection and go back to reading keys.
3244 if (IsListEmpty (&gMenuOption
)) {
3245 ControlFlag
= CfReadKey
;
3251 Index
< ARRAY_SIZE (gScreenOperationToControlFlag
);
3254 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3255 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3262 ControlFlag
= CfRepaint
;
3264 ASSERT(MenuOption
!= NULL
);
3265 Statement
= MenuOption
->ThisTag
;
3266 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
3270 switch (Statement
->OpCode
->OpCode
) {
3271 case EFI_IFR_REF_OP
:
3272 case EFI_IFR_ACTION_OP
:
3273 case EFI_IFR_RESET_BUTTON_OP
:
3274 ControlFlag
= CfExit
;
3279 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3281 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
3282 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3284 if (OptionString
!= NULL
) {
3285 FreePool (OptionString
);
3288 if (EFI_ERROR (Status
)) {
3291 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
3294 ControlFlag
= CfExit
;
3302 // We come here when someone press ESC
3303 // If the policy is not exit front page when user press ESC, process here.
3305 if (!FormExitPolicy()) {
3308 ControlFlag
= CfRepaint
;
3312 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3313 ControlFlag
= CfExit
;
3317 ControlFlag
= CfRepaint
;
3319 ASSERT (HotKey
!= NULL
);
3321 if (FxConfirmPopup(HotKey
->Action
)) {
3322 gUserInput
->Action
= HotKey
->Action
;
3323 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3324 gUserInput
->DefaultId
= HotKey
->DefaultId
;
3326 ControlFlag
= CfExit
;
3330 ControlFlag
= CfRepaint
;
3336 ControlFlag
= CfRepaint
;
3337 ASSERT(MenuOption
!= NULL
);
3338 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3339 if (MenuOption
->Sequence
!= 0) {
3341 // In the middle or tail of the Date/Time op-code set, go left.
3343 ASSERT(NewPos
!= NULL
);
3344 NewPos
= NewPos
->BackLink
;
3350 ControlFlag
= CfRepaint
;
3351 ASSERT(MenuOption
!= NULL
);
3352 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3353 if (MenuOption
->Sequence
!= 2) {
3355 // In the middle or tail of the Date/Time op-code set, go left.
3357 ASSERT(NewPos
!= NULL
);
3358 NewPos
= NewPos
->ForwardLink
;
3364 ControlFlag
= CfRepaint
;
3367 SavedListEntry
= NewPos
;
3368 ASSERT(NewPos
!= NULL
);
3370 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3371 ASSERT (MenuOption
!= NULL
);
3374 // Adjust Date/Time position before we advance forward.
3376 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3378 NewPos
= NewPos
->BackLink
;
3380 // Find next selectable menu or the first menu beyond current form.
3382 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
, FALSE
);
3383 if (Difference
< 0) {
3385 // We hit the begining MenuOption that can be focused
3386 // so we simply scroll to the top.
3389 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3390 TopOfScreen
= gMenuOption
.ForwardLink
;
3391 NewPos
= SavedListEntry
;
3395 // Scroll up to the last page when we have arrived at top page.
3397 TopOfScreen
= FindTopOfScreenMenu (gMenuOption
.BackLink
, BottomRow
- TopRow
, &SkipValue
);
3398 NewPos
= gMenuOption
.BackLink
;
3399 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3402 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3404 if (MenuOption
->Row
< TopRow
+ Difference
+ NextMenuOption
->Skip
) {
3406 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3408 TopOfScreen
= NewPos
;
3414 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3416 // BottomRow - TopRow + 1 means the total rows current forms supported.
3417 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3418 // and new top menu. New top menu will all shows in next form, but last highlight menu
3419 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3420 // last highlight menu.
3422 if (!IsSelectable(NextMenuOption
) && IsSelectable(MenuOption
) &&
3423 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3424 NewPos
= SavedListEntry
;
3428 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3431 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3433 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3434 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3436 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3441 // SkipValue means lines is skipped when show the top menu option.
3443 ControlFlag
= CfRepaint
;
3449 // First minus the menu of the top screen, it's value is SkipValue.
3451 if (SkipValue
>= BottomRow
- TopRow
+ 1) {
3453 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
3454 // form of options to be show, so just update the SkipValue to show the next
3455 // parts of options.
3457 SkipValue
-= BottomRow
- TopRow
+ 1;
3458 NewPos
= TopOfScreen
;
3461 Index
= (BottomRow
+ 1) - SkipValue
- TopRow
;
3464 TopOfScreen
= FindTopOfScreenMenu(TopOfScreen
, Index
, &SkipValue
);
3465 NewPos
= TopOfScreen
;
3466 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, FALSE
);
3468 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3471 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3472 // Don't do this when we are already in the first page.
3474 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3475 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3477 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3482 // SkipValue means lines is skipped when show the top menu option.
3484 ControlFlag
= CfRepaint
;
3489 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3490 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
3492 // Count to the menu option which will show at the top of the next form.
3494 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
3495 Link
= Link
->ForwardLink
;
3496 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3497 Index
= Index
+ NextMenuOption
->Skip
;
3500 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
3502 // Highlight on the last menu which can be highlight.
3505 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
, TRUE
);
3508 // Calculate the skip line for top of screen menu.
3510 if (Link
== TopOfScreen
) {
3512 // The top of screen menu option occupies the entire form.
3514 SkipValue
+= BottomRow
- TopRow
+ 1;
3516 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3521 // Move to the Next selectable menu.
3523 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
, TRUE
);
3527 // Save the menu as the next highlight menu.
3531 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3534 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3535 // Don't do this when we are already in the last page.
3537 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3538 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3540 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3545 // SkipValue means lines is skipped when show the top menu option.
3546 // NewPos points to the menu which is highlighted now.
3548 ControlFlag
= CfRepaint
;
3551 if (NewPos
== TopOfScreen
) {
3557 SavedListEntry
= NewPos
;
3559 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3560 // to be one that progresses to the next set of op-codes, we need to advance to the last
3561 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3562 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3563 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3564 // the Date/Time op-code.
3566 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3568 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3569 NewPos
= NewPos
->ForwardLink
;
3571 // Find the next selectable menu.
3573 if (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
> BottomRow
+ 1) {
3574 if (gMenuOption
.ForwardLink
== NewPos
|| &gMenuOption
== NewPos
) {
3580 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
+ 1 - (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
), FALSE
);
3582 if (Difference
< 0) {
3584 // Scroll to the first page.
3586 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3587 TopOfScreen
= gMenuOption
.ForwardLink
;
3591 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3593 NewPos
= gMenuOption
.ForwardLink
;
3594 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3598 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3600 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3601 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3603 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3608 // Get next selected menu info.
3610 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3611 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3612 if (NextMenuOption
->Row
== 0) {
3613 UpdateOptionSkipLines (NextMenuOption
);
3617 // Calculate new highlight menu end row.
3619 Temp
= (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
) + Difference
+ NextMenuOption
->Skip
- 1;
3620 if (Temp
> BottomRow
) {
3622 // Get the top screen menu info.
3624 AdjustDateAndTimePosition (FALSE
, &TopOfScreen
);
3625 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3628 // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
3629 // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
3631 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3633 // Skip the top op-code
3635 TopOfScreen
= TopOfScreen
->ForwardLink
;
3636 DistanceValue
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3638 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3641 // If we have a remainder, skip that many more op-codes until we drain the remainder
3642 // Special case is the selected highlight menu has more than one form of menus.
3644 while (DistanceValue
>= SavedMenuOption
->Skip
&& TopOfScreen
!= NewPos
) {
3646 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3648 DistanceValue
= DistanceValue
- (INTN
) SavedMenuOption
->Skip
;
3649 TopOfScreen
= TopOfScreen
->ForwardLink
;
3650 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3653 // Since we will act on this op-code in the next routine, and increment the
3654 // SkipValue, set the skips to one less than what is required.
3656 if (TopOfScreen
!= NewPos
) {
3657 SkipValue
= DistanceValue
;
3663 // Since we will act on this op-code in the next routine, and increment the
3664 // SkipValue, set the skips to one less than what is required.
3666 SkipValue
+= Temp
- BottomRow
;
3669 } else if (!IsSelectable (NextMenuOption
)) {
3671 // Continue to go down until scroll to next page or the selectable option is found.
3673 ScreenOperation
= UiDown
;
3674 ControlFlag
= CfScreenOperation
;
3678 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3681 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3683 // BottomRow - TopRow + 1 means the total rows current forms supported.
3684 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3685 // and new top menu. New top menu will all shows in next form, but last highlight menu
3686 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3687 // last highlight menu.
3689 if (!IsSelectable (NextMenuOption
) && IsSelectable (MenuOption
) &&
3690 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3691 NewPos
= SavedListEntry
;
3694 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3697 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3699 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3700 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3702 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3705 case CfUiNoOperation
:
3706 ControlFlag
= CfRepaint
;
3710 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3711 if (HelpString
!= NULL
) {
3712 FreePool (HelpString
);
3714 if (HelpHeaderString
!= NULL
) {
3715 FreePool (HelpHeaderString
);
3717 if (HelpBottomString
!= NULL
) {
3718 FreePool (HelpBottomString
);
3729 Free the UI Menu Option structure data.
3731 @param MenuOptionList Point to the menu option list which need to be free.
3736 LIST_ENTRY
*MenuOptionList
3740 UI_MENU_OPTION
*Option
;
3743 // Free menu option list
3745 while (!IsListEmpty (MenuOptionList
)) {
3746 Link
= GetFirstNode (MenuOptionList
);
3747 Option
= MENU_OPTION_FROM_LINK (Link
);
3748 if (Option
->Description
!= NULL
){
3749 FreePool(Option
->Description
);
3751 RemoveEntryList (&Option
->Link
);
3758 Base on the browser status info to show an pop up message.
3762 BrowserStatusProcess (
3768 EFI_EVENT WaitList
[2];
3769 EFI_EVENT RefreshIntervalEvent
;
3770 EFI_EVENT TimeOutEvent
;
3774 WARNING_IF_CONTEXT EventContext
;
3775 EFI_IFR_OP_HEADER
*OpCodeBuf
;
3776 EFI_STRING_ID StringToken
;
3777 CHAR16 DiscardChange
;
3778 CHAR16 JumpToFormSet
;
3779 CHAR16
*PrintString
;
3781 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3786 TimeOutEvent
= NULL
;
3787 RefreshIntervalEvent
= NULL
;
3789 if (gFormData
->HighLightedStatement
!= NULL
) {
3790 OpCodeBuf
= gFormData
->HighLightedStatement
->OpCode
;
3793 if (gFormData
->BrowserStatus
== (BROWSER_WARNING_IF
)) {
3794 ASSERT (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_WARNING_IF_OP
);
3796 TimeOut
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->TimeOut
;
3797 StringToken
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->Warning
;
3800 if ((gFormData
->BrowserStatus
== (BROWSER_NO_SUBMIT_IF
)) &&
3801 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_NO_SUBMIT_IF_OP
)) {
3802 StringToken
= ((EFI_IFR_NO_SUBMIT_IF
*) OpCodeBuf
)->Error
;
3803 } else if ((gFormData
->BrowserStatus
== (BROWSER_INCONSISTENT_IF
)) &&
3804 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_INCONSISTENT_IF_OP
)) {
3805 StringToken
= ((EFI_IFR_INCONSISTENT_IF
*) OpCodeBuf
)->Error
;
3809 if (StringToken
!= 0) {
3810 ErrorInfo
= GetToken (StringToken
, gFormData
->HiiHandle
);
3811 } else if (gFormData
->ErrorString
!= NULL
) {
3813 // Only used to compatible with old setup browser.
3814 // Not use this field in new browser core.
3816 ErrorInfo
= gFormData
->ErrorString
;
3818 switch (gFormData
->BrowserStatus
) {
3819 case BROWSER_SUBMIT_FAIL
:
3820 ErrorInfo
= gSaveFailed
;
3823 case BROWSER_FORM_NOT_FOUND
:
3824 ErrorInfo
= gFormNotFound
;
3827 case BROWSER_FORM_SUPPRESS
:
3828 ErrorInfo
= gFormSuppress
;
3831 case BROWSER_PROTOCOL_NOT_FOUND
:
3832 ErrorInfo
= gProtocolNotFound
;
3835 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3836 ErrorInfo
= gNoSubmitIfFailed
;
3839 case BROWSER_RECONNECT_FAIL
:
3840 ErrorInfo
= gReconnectFail
;
3843 case BROWSER_RECONNECT_SAVE_CHANGES
:
3844 ErrorInfo
= gReconnectConfirmChanges
;
3847 case BROWSER_RECONNECT_REQUIRED
:
3848 ErrorInfo
= gReconnectRequired
;
3852 ErrorInfo
= gBrowserError
;
3857 switch (gFormData
->BrowserStatus
) {
3858 case BROWSER_SUBMIT_FAIL
:
3859 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3860 case BROWSER_RECONNECT_SAVE_CHANGES
:
3861 ASSERT (gUserInput
!= NULL
);
3862 if (gFormData
->BrowserStatus
== (BROWSER_SUBMIT_FAIL
)) {
3863 PrintString
= gSaveProcess
;
3864 JumpToFormSet
= gJumpToFormSet
[0];
3865 DiscardChange
= gDiscardChange
[0];
3866 } else if (gFormData
->BrowserStatus
== (BROWSER_RECONNECT_SAVE_CHANGES
)){
3867 PrintString
= gChangesOpt
;
3868 JumpToFormSet
= gConfirmOptYes
[0];
3869 DiscardChange
= gConfirmOptNo
[0];
3871 PrintString
= gSaveNoSubmitProcess
;
3872 JumpToFormSet
= gCheckError
[0];
3873 DiscardChange
= gDiscardChange
[0];
3877 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, PrintString
, gEmptyString
, NULL
);
3878 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) &&
3879 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (JumpToFormSet
| UPPER_LOWER_CASE_OFFSET
)));
3881 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) {
3882 gUserInput
->Action
= BROWSER_ACTION_DISCARD
;
3884 gUserInput
->Action
= BROWSER_ACTION_GOTO
;
3891 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3892 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3894 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
3895 ASSERT_EFI_ERROR (Status
);
3897 EventContext
.SyncEvent
= TimeOutEvent
;
3898 EventContext
.TimeOut
= &TimeOut
;
3899 EventContext
.ErrorInfo
= ErrorInfo
;
3901 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
3902 ASSERT_EFI_ERROR (Status
);
3905 // Show the dialog first to avoid long time not reaction.
3907 gBS
->SignalEvent (RefreshIntervalEvent
);
3909 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
3910 ASSERT_EFI_ERROR (Status
);
3913 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3914 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3918 if (Status
!= EFI_NOT_READY
) {
3922 WaitList
[0] = TimeOutEvent
;
3923 WaitList
[1] = gST
->ConIn
->WaitForKey
;
3925 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
3926 ASSERT_EFI_ERROR (Status
);
3930 // Timeout occur, close the hoot time out event.
3936 gBS
->CloseEvent (TimeOutEvent
);
3937 gBS
->CloseEvent (RefreshIntervalEvent
);
3942 if (StringToken
!= 0) {
3943 FreePool (ErrorInfo
);
3948 Display one form, and return user input.
3950 @param FormData Form Data to be shown.
3951 @param UserInputData User input data.
3953 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
3954 2.Error info has show and return.
3955 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
3956 @retval EFI_NOT_FOUND New form data has some error.
3961 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
3962 OUT USER_INPUT
*UserInputData
3967 ASSERT (FormData
!= NULL
);
3968 if (FormData
== NULL
) {
3969 return EFI_INVALID_PARAMETER
;
3972 gUserInput
= UserInputData
;
3973 gFormData
= FormData
;
3976 // Process the status info first.
3978 BrowserStatusProcess();
3979 if (gFormData
->BrowserStatus
!= BROWSER_SUCCESS
) {
3981 // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
3986 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
3987 if (EFI_ERROR (Status
)) {
3992 // Global Widths should be initialized before any MenuOption creation
3993 // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
3997 // |<-.->|<-.........->|<- .........->|<-...........->|
3998 // Skip Prompt Option Help
4000 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3) + 1;
4001 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- 1 - LEFT_SKIPPED_COLUMNS
);
4002 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gOptionBlockWidth
- 1) - 1);
4004 ConvertStatementToMenu();
4007 // Check whether layout is changed.
4010 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
4011 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
4012 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
4013 mStatementLayoutIsChanged
= TRUE
;
4015 mStatementLayoutIsChanged
= FALSE
;
4018 Status
= UiDisplayMenu(FormData
);
4021 // Backup last form info.
4023 mIsFirstForm
= FALSE
;
4024 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
4025 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
4026 gOldFormEntry
.FormId
= FormData
->FormId
;
4029 //Free the Ui menu option list.
4031 FreeMenuOptionData(&gMenuOption
);
4037 Clear Screen to the initial state.
4041 DriverClearDisplayPage (
4045 ClearDisplayPage ();
4046 mIsFirstForm
= TRUE
;
4050 Set Buffer to Value for Size bytes.
4052 @param Buffer Memory to set.
4053 @param Size Number of bytes to set
4054 @param Value Value of the set operation.
4067 while ((Size
--) != 0) {
4073 Initialize Setup Browser driver.
4075 @param ImageHandle The image handle.
4076 @param SystemTable The system table.
4078 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
4079 @return Other value if failed to initialize the Setup Browser module.
4084 InitializeDisplayEngine (
4085 IN EFI_HANDLE ImageHandle
,
4086 IN EFI_SYSTEM_TABLE
*SystemTable
4090 EFI_INPUT_KEY HotKey
;
4091 EFI_STRING NewString
;
4092 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
4095 // Publish our HII data
4097 gHiiHandle
= HiiAddPackages (
4098 &gDisplayEngineGuid
,
4100 DisplayEngineStrings
,
4103 ASSERT (gHiiHandle
!= NULL
);
4106 // Install Form Display protocol
4108 Status
= gBS
->InstallProtocolInterface (
4109 &mPrivateData
.Handle
,
4110 &gEdkiiFormDisplayEngineProtocolGuid
,
4111 EFI_NATIVE_INTERFACE
,
4112 &mPrivateData
.FromDisplayProt
4114 ASSERT_EFI_ERROR (Status
);
4116 InitializeDisplayStrings();
4118 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
4119 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
4122 // Use BrowserEx2 protocol to register HotKey.
4124 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
4125 if (!EFI_ERROR (Status
)) {
4127 // Register the default HotKey F9 and F10 again.
4129 HotKey
.UnicodeChar
= CHAR_NULL
;
4130 HotKey
.ScanCode
= SCAN_F10
;
4131 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
4132 ASSERT (NewString
!= NULL
);
4133 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
4135 HotKey
.ScanCode
= SCAN_F9
;
4136 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
4137 ASSERT (NewString
!= NULL
);
4138 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
4145 This is the default unload handle for display core drivers.
4147 @param[in] ImageHandle The drivers' driver image.
4149 @retval EFI_SUCCESS The image is unloaded.
4150 @retval Others Failed to unload the image.
4155 UnloadDisplayEngine (
4156 IN EFI_HANDLE ImageHandle
4159 HiiRemovePackages(gHiiHandle
);
4161 FreeDisplayStrings ();
4163 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
4164 FreePool (gHighligthMenuInfo
.HLTOpCode
);
4167 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
4168 FreePool (gHighligthMenuInfo
.TOSOpCode
);