2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "FormDisplay.h"
13 // Search table for UiDisplayMenu()
15 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
46 UINTN mScanCodeNumber
= ARRAY_SIZE (gScanCodeToOperation
);
48 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
91 EFI_GUID gDisplayEngineGuid
= {
92 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
96 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
97 BOOLEAN mStatementLayoutIsChanged
= TRUE
;
98 USER_INPUT
*gUserInput
;
99 FORM_DISPLAY_ENGINE_FORM
*gFormData
;
100 EFI_HII_HANDLE gHiiHandle
;
102 LIST_ENTRY gMenuOption
;
103 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo
= {0};
104 BOOLEAN mIsFirstForm
= TRUE
;
105 FORM_ENTRY_INFO gOldFormEntry
= {0};
108 // Browser Global Strings
110 CHAR16
*gReconnectConfirmChanges
;
111 CHAR16
*gReconnectFail
;
112 CHAR16
*gReconnectRequired
;
114 CHAR16
*gFormNotFound
;
116 CHAR16
*gBrowserError
;
118 CHAR16
*gNoSubmitIfFailed
;
119 CHAR16
*gSaveProcess
;
120 CHAR16
*gSaveNoSubmitProcess
;
121 CHAR16
*gDiscardChange
;
122 CHAR16
*gJumpToFormSet
;
124 CHAR16
*gPromptForData
;
125 CHAR16
*gPromptForPassword
;
126 CHAR16
*gPromptForNewPassword
;
127 CHAR16
*gConfirmPassword
;
128 CHAR16
*gConfirmError
;
129 CHAR16
*gPassowordInvalid
;
131 CHAR16
*gEmptyString
;
133 CHAR16
*gOptionMismatch
;
134 CHAR16
*gFormSuppress
;
135 CHAR16
*gProtocolNotFound
;
136 CHAR16
*gConfirmDefaultMsg
;
137 CHAR16
*gConfirmSubmitMsg
;
138 CHAR16
*gConfirmDiscardMsg
;
139 CHAR16
*gConfirmResetMsg
;
140 CHAR16
*gConfirmExitMsg
;
141 CHAR16
*gConfirmSubmitMsg2nd
;
142 CHAR16
*gConfirmDefaultMsg2nd
;
143 CHAR16
*gConfirmResetMsg2nd
;
144 CHAR16
*gConfirmExitMsg2nd
;
146 CHAR16
*gConfirmOptYes
;
147 CHAR16
*gConfirmOptNo
;
148 CHAR16
*gConfirmOptOk
;
149 CHAR16
*gConfirmOptCancel
;
153 CHAR16
*gCancelOption
;
155 CHAR16
*gWarningPopup
;
157 CHAR16
*gConfirmMsgConnect
;
158 CHAR16
*gConfirmMsgEnd
;
159 CHAR16
*gPasswordUnsupported
;
160 CHAR16 gModalSkipColumn
;
161 CHAR16 gPromptBlockWidth
;
162 CHAR16 gOptionBlockWidth
;
163 CHAR16 gHelpBlockWidth
;
164 CHAR16
*mUnknownString
;
166 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
167 FORM_DISPLAY_DRIVER_SIGNATURE
,
171 DriverClearDisplayPage
,
175 EFI_HII_POPUP_PROTOCOL_REVISION
,
182 Get the string based on the StringId and HII Package List Handle.
184 @param Token The String's ID.
185 @param HiiHandle The package list in the HII database to search for
186 the specified string.
188 @return The output string.
193 IN EFI_STRING_ID Token
,
194 IN EFI_HII_HANDLE HiiHandle
199 String
= HiiGetString (HiiHandle
, Token
, NULL
);
200 if (String
== NULL
) {
201 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
202 ASSERT (String
!= NULL
);
205 return (CHAR16
*) String
;
210 Initialize the HII String Token to the correct values.
214 InitializeDisplayStrings (
218 gReconnectConfirmChanges
= GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES
), gHiiHandle
);
219 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
220 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
221 gNoSubmitIfFailed
= GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED
), gHiiHandle
);
222 gReconnectFail
= GetToken (STRING_TOKEN (RECONNECT_FAILED
), gHiiHandle
);
223 gReconnectRequired
= GetToken (STRING_TOKEN (RECONNECT_REQUIRED
), gHiiHandle
);
224 gChangesOpt
= GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS
), gHiiHandle
);
225 gSaveProcess
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP
), gHiiHandle
);
226 gSaveNoSubmitProcess
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK
), gHiiHandle
);
227 gDiscardChange
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD
), gHiiHandle
);
228 gJumpToFormSet
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP
), gHiiHandle
);
229 gCheckError
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK
), gHiiHandle
);
230 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
231 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
232 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
233 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
234 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
235 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
236 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
237 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
238 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
239 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
240 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
241 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
242 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
243 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
244 gBrowserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
245 gConfirmDefaultMsg
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE
), gHiiHandle
);
246 gConfirmDiscardMsg
= GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE
), gHiiHandle
);
247 gConfirmSubmitMsg
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE
), gHiiHandle
);
248 gConfirmResetMsg
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE
), gHiiHandle
);
249 gConfirmExitMsg
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE
), gHiiHandle
);
250 gConfirmDefaultMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND
), gHiiHandle
);
251 gConfirmSubmitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND
), gHiiHandle
);
252 gConfirmResetMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND
), gHiiHandle
);
253 gConfirmExitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND
), gHiiHandle
);
254 gConfirmOpt
= GetToken (STRING_TOKEN (CONFIRM_OPTION
), gHiiHandle
);
255 gConfirmOptYes
= GetToken (STRING_TOKEN (CONFIRM_OPTION_YES
), gHiiHandle
);
256 gConfirmOptNo
= GetToken (STRING_TOKEN (CONFIRM_OPTION_NO
), gHiiHandle
);
257 gConfirmOptOk
= GetToken (STRING_TOKEN (CONFIRM_OPTION_OK
), gHiiHandle
);
258 gConfirmOptCancel
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CANCEL
), gHiiHandle
);
259 gYesOption
= GetToken (STRING_TOKEN (YES_SELECTABLE_OPTION
), gHiiHandle
);
260 gNoOption
= GetToken (STRING_TOKEN (NO_SELECTABLE_OPTION
), gHiiHandle
);
261 gOkOption
= GetToken (STRING_TOKEN (OK_SELECTABLE_OPTION
), gHiiHandle
);
262 gCancelOption
= GetToken (STRING_TOKEN (CANCEL_SELECTABLE_OPTION
), gHiiHandle
);
263 gErrorPopup
= GetToken (STRING_TOKEN (ERROR_POPUP_STRING
), gHiiHandle
);
264 gWarningPopup
= GetToken (STRING_TOKEN (WARNING_POPUP_STRING
), gHiiHandle
);
265 gInfoPopup
= GetToken (STRING_TOKEN (INFO_POPUP_STRING
), gHiiHandle
);
266 gConfirmMsgConnect
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT
), gHiiHandle
);
267 gConfirmMsgEnd
= GetToken (STRING_TOKEN (CONFIRM_OPTION_END
), gHiiHandle
);
268 gPasswordUnsupported
= GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED
), gHiiHandle
);
272 Free up the resource allocated for all strings required
281 FreePool (mUnknownString
);
282 FreePool (gEmptyString
);
283 FreePool (gSaveFailed
);
284 FreePool (gNoSubmitIfFailed
);
285 FreePool (gReconnectFail
);
286 FreePool (gReconnectRequired
);
287 FreePool (gChangesOpt
);
288 FreePool (gReconnectConfirmChanges
);
289 FreePool (gSaveProcess
);
290 FreePool (gSaveNoSubmitProcess
);
291 FreePool (gDiscardChange
);
292 FreePool (gJumpToFormSet
);
293 FreePool (gCheckError
);
294 FreePool (gPromptForData
);
295 FreePool (gPromptForPassword
);
296 FreePool (gPromptForNewPassword
);
297 FreePool (gConfirmPassword
);
298 FreePool (gConfirmError
);
299 FreePool (gPassowordInvalid
);
300 FreePool (gPressEnter
);
301 FreePool (gMiniString
);
302 FreePool (gOptionMismatch
);
303 FreePool (gFormSuppress
);
304 FreePool (gProtocolNotFound
);
305 FreePool (gBrowserError
);
306 FreePool (gNoSubmitIf
);
307 FreePool (gFormNotFound
);
308 FreePool (gConfirmDefaultMsg
);
309 FreePool (gConfirmSubmitMsg
);
310 FreePool (gConfirmDiscardMsg
);
311 FreePool (gConfirmResetMsg
);
312 FreePool (gConfirmExitMsg
);
313 FreePool (gConfirmDefaultMsg2nd
);
314 FreePool (gConfirmSubmitMsg2nd
);
315 FreePool (gConfirmResetMsg2nd
);
316 FreePool (gConfirmExitMsg2nd
);
317 FreePool (gConfirmOpt
);
318 FreePool (gConfirmOptYes
);
319 FreePool (gConfirmOptNo
);
320 FreePool (gConfirmOptOk
);
321 FreePool (gConfirmOptCancel
);
322 FreePool (gYesOption
);
323 FreePool (gNoOption
);
324 FreePool (gOkOption
);
325 FreePool (gCancelOption
);
326 FreePool (gErrorPopup
);
327 FreePool (gWarningPopup
);
328 FreePool (gInfoPopup
);
329 FreePool (gConfirmMsgConnect
);
330 FreePool (gConfirmMsgEnd
);
331 FreePool (gPasswordUnsupported
);
335 Get prompt string id from the opcode data buffer.
337 @param OpCode The input opcode buffer.
339 @return The prompt string id.
344 IN EFI_IFR_OP_HEADER
*OpCode
347 EFI_IFR_STATEMENT_HEADER
*Header
;
349 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
353 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
355 return Header
->Prompt
;
359 Get the supported width for a particular op-code
361 @param MenuOption The menu option.
362 @param AdjustWidth The width which is saved for the space.
364 @return Returns the number of CHAR16 characters that is support.
369 IN UI_MENU_OPTION
*MenuOption
,
370 OUT UINT16
*AdjustWidth
375 EFI_IFR_TEXT
*TextOp
;
377 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
379 Statement
= MenuOption
->ThisTag
;
382 // For modal form, clean the entire row.
384 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
385 if (AdjustWidth
!= NULL
) {
386 *AdjustWidth
= LEFT_SKIPPED_COLUMNS
;
388 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gModalSkipColumn
+ LEFT_SKIPPED_COLUMNS
));
394 // See if the second text parameter is really NULL
396 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
397 TextOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
398 if (TextOp
->TextTwo
!= 0) {
399 String
= GetToken (TextOp
->TextTwo
, gFormData
->HiiHandle
);
400 Size
= StrLen (String
);
405 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
406 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
407 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
408 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
409 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
411 // Allow a wide display if text op-code and no secondary text op-code
413 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
417 // Return the space width.
419 if (AdjustWidth
!= NULL
) {
423 // Keep consistent with current behavior.
425 ReturnWidth
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
427 if (AdjustWidth
!= NULL
) {
431 ReturnWidth
= (UINT16
) (gPromptBlockWidth
- 1);
435 // For nest in statement, should the subtitle indent.
437 if (MenuOption
->NestInStatement
) {
438 ReturnWidth
-= SUBTITLE_INDENT
;
445 Will copy LineWidth amount of a string in the OutputString buffer and return the
446 number of CHAR16 characters that were copied into the OutputString buffer.
447 The output string format is:
448 Glyph Info + String info + '\0'.
450 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
452 @param InputString String description for this option.
453 @param LineWidth Width of the desired string to extract in CHAR16
455 @param GlyphWidth The glyph width of the begin of the char in the string.
456 @param Index Where in InputString to start the copy process
457 @param OutputString Buffer to copy the string into
459 @return Returns the number of CHAR16 characters that were copied into the OutputString
460 buffer, include extra glyph info and '\0' info.
465 IN CHAR16
*InputString
,
467 IN OUT UINT16
*GlyphWidth
,
469 OUT CHAR16
**OutputString
474 UINT16 OriginalGlyphWidth
;
476 UINT16 LastSpaceOffset
;
477 UINT16 LastGlyphWidth
;
479 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
483 if (LineWidth
== 0 || *GlyphWidth
== 0) {
488 // Save original glyph width.
490 OriginalGlyphWidth
= *GlyphWidth
;
491 LastGlyphWidth
= OriginalGlyphWidth
;
496 // 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.
497 // To avoid displaying this empty line in screen, just skip the two CHARs here.
499 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
504 // Fast-forward the string and see if there is a carriage-return in the string
506 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
507 switch (InputString
[*Index
+ StrOffset
]) {
516 case CHAR_CARRIAGE_RETURN
:
523 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
526 // Record the last space info in this line. Will be used in rewind.
528 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
529 LastSpaceOffset
= StrOffset
;
530 LastGlyphWidth
= *GlyphWidth
;
541 // Rewind the string from the maximum size until we see a space to break the line
543 if (GlyphOffset
> LineWidth
) {
545 // Rewind the string to last space char in this line.
547 if (LastSpaceOffset
!= 0) {
548 StrOffset
= LastSpaceOffset
;
549 *GlyphWidth
= LastGlyphWidth
;
552 // Roll back to last char in the line width.
559 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
561 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
566 // Need extra glyph info and '\0' info, so +2.
568 *OutputString
= AllocateZeroPool ((StrOffset
+ 2) * sizeof(CHAR16
));
569 if (*OutputString
== NULL
) {
574 // Save the glyph info at the begin of the string, will used by Print function.
576 if (OriginalGlyphWidth
== 1) {
577 *(*OutputString
) = NARROW_CHAR
;
579 *(*OutputString
) = WIDE_CHAR
;
582 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
584 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
586 // Skip the space info at the begin of next line.
588 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
589 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
591 // Skip the /n or /n/r info.
593 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
594 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
596 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
598 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
600 // Skip the /r or /r/n info.
602 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
603 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
605 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
608 *Index
= (UINT16
) (*Index
+ StrOffset
);
612 // Include extra glyph info and '\0' info, so +2.
614 return StrOffset
+ 2;
618 Add one menu option by specified description and context.
620 @param Statement Statement of this Menu Option.
621 @param MenuItemCount The index for this Option in the Menu.
622 @param NestIn Whether this statement is nest in another statement.
627 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
628 IN UINT16
*MenuItemCount
,
632 UI_MENU_OPTION
*MenuOption
;
635 UINT16 NumberOfLines
;
639 CHAR16
*OutputString
;
640 EFI_STRING_ID PromptId
;
648 PromptId
= GetPrompt (Statement
->OpCode
);
649 ASSERT (PromptId
!= 0);
651 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
655 for (Index
= 0; Index
< Count
; Index
++) {
656 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
659 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
660 MenuOption
->Description
= GetToken (PromptId
, gFormData
->HiiHandle
);
661 MenuOption
->Handle
= gFormData
->HiiHandle
;
662 MenuOption
->ThisTag
= Statement
;
663 MenuOption
->NestInStatement
= NestIn
;
664 MenuOption
->EntryNumber
= *MenuItemCount
;
666 MenuOption
->Sequence
= Index
;
668 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
669 MenuOption
->GrayOut
= TRUE
;
671 MenuOption
->GrayOut
= FALSE
;
674 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
675 MenuOption
->GrayOut
= TRUE
;
679 // If the form or the question has the lock attribute, deal same as grayout.
681 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
682 MenuOption
->GrayOut
= TRUE
;
685 switch (Statement
->OpCode
->OpCode
) {
686 case EFI_IFR_ORDERED_LIST_OP
:
687 case EFI_IFR_ONE_OF_OP
:
688 case EFI_IFR_NUMERIC_OP
:
689 case EFI_IFR_TIME_OP
:
690 case EFI_IFR_DATE_OP
:
691 case EFI_IFR_CHECKBOX_OP
:
692 case EFI_IFR_PASSWORD_OP
:
693 case EFI_IFR_STRING_OP
:
695 // User could change the value of these items
697 MenuOption
->IsQuestion
= TRUE
;
699 case EFI_IFR_TEXT_OP
:
700 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
702 // Initializing GrayOut option as TRUE for Text setup options
703 // so that those options will be Gray in colour and un selectable.
705 MenuOption
->GrayOut
= TRUE
;
709 MenuOption
->IsQuestion
= FALSE
;
713 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
714 MenuOption
->ReadOnly
= TRUE
;
715 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
716 MenuOption
->GrayOut
= TRUE
;
721 (Statement
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
722 (Statement
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
723 Width
= GetWidth (MenuOption
, NULL
);
724 for (; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
726 // If there is more string to process print on the next row and increment the Skip value
728 if (StrLen (&MenuOption
->Description
[ArrayEntry
]) != 0) {
731 FreePool (OutputString
);
735 // Add three MenuOptions for Date/Time
736 // Data format : [01/02/2004] [11:22:33]
737 // Line number : 0 0 1 0 0 1
744 // Override LineNumber for the MenuOption in Date/Time sequence
746 MenuOption
->Skip
= 1;
748 MenuOption
->Skip
= NumberOfLines
;
751 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
758 Create the menu list base on the form data info.
762 ConvertStatementToMenu (
766 UINT16 MenuItemCount
;
768 LIST_ENTRY
*NestLink
;
769 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
770 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
773 InitializeListHead (&gMenuOption
);
775 Link
= GetFirstNode (&gFormData
->StatementListHead
);
776 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
777 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
778 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
781 // Skip the opcode not recognized by Display core.
783 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
787 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
790 // Check the statement nest in this host statement.
792 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
793 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
794 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
795 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
798 // Skip the opcode not recognized by Display core.
800 if (NestStatement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
804 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
810 Count the storage space of a Unicode string.
812 This function handles the Unicode string with NARROW_CHAR
813 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
814 does not count in the resultant output. If a WIDE_CHAR is
815 hit, then 2 Unicode character will consume an output storage
816 space with size of CHAR16 till a NARROW_CHAR is hit.
818 If String is NULL, then ASSERT ().
820 @param String The input string to be counted.
822 @return Storage space for the input string.
832 UINTN IncrementValue
;
834 ASSERT (String
!= NULL
);
835 if (String
== NULL
) {
845 // Advance to the null-terminator or to the first width directive
848 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
849 Index
++, Count
= Count
+ IncrementValue
854 // We hit the null-terminator, we now have a count
856 if (String
[Index
] == 0) {
860 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
861 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
863 if (String
[Index
] == NARROW_CHAR
) {
865 // Skip to the next character
871 // Skip to the next character
876 } while (String
[Index
] != 0);
879 // Increment by one to include the null-terminator in the size
883 return Count
* sizeof (CHAR16
);
887 Base on the input option string to update the skip value for a menu option.
889 @param MenuOption The MenuOption to be checked.
890 @param OptionString The input option string.
894 UpdateSkipInfoForMenu (
895 IN UI_MENU_OPTION
*MenuOption
,
896 IN CHAR16
*OptionString
902 CHAR16
*OutputString
;
905 Width
= (UINT16
) gOptionBlockWidth
- 1;
909 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
910 if (StrLen (&OptionString
[Index
]) != 0) {
914 FreePool (OutputString
);
917 if ((Row
> MenuOption
->Skip
) &&
918 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
919 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
920 MenuOption
->Skip
= Row
;
925 Update display lines for a Menu Option.
927 @param MenuOption The MenuOption to be checked.
931 UpdateOptionSkipLines (
932 IN UI_MENU_OPTION
*MenuOption
935 CHAR16
*OptionString
;
939 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
940 if (OptionString
!= NULL
) {
941 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
943 FreePool (OptionString
);
946 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
947 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
949 if (OptionString
!= NULL
) {
950 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
952 FreePool (OptionString
);
958 Check whether this Menu Option could be print.
960 Check Prompt string, option string or text two string not NULL.
962 This is an internal function.
964 @param MenuOption The MenuOption to be checked.
966 @retval TRUE This Menu Option is printable.
967 @retval FALSE This Menu Option could not be printable.
972 UI_MENU_OPTION
*MenuOption
976 EFI_STRING OptionString
;
980 if (MenuOption
->Description
[0] != '\0') {
984 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
985 if (EFI_ERROR (Status
)) {
988 if (OptionString
!= NULL
&& OptionString
[0] != '\0') {
989 FreePool (OptionString
);
993 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
994 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
995 ASSERT (OptionString
!= NULL
);
996 if (OptionString
[0] != '\0'){
997 FreePool (OptionString
);
1006 Check whether this Menu Option could be highlighted.
1008 This is an internal function.
1010 @param MenuOption The MenuOption to be checked.
1012 @retval TRUE This Menu Option is selectable.
1013 @retval FALSE This Menu Option could not be selected.
1018 UI_MENU_OPTION
*MenuOption
1021 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
1022 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
|| !PrintableMenu (MenuOption
)) {
1030 Move to next selectable statement.
1032 This is an internal function.
1034 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1035 @param CurrentPosition Current position.
1036 @param GapToTop Gap position to top or bottom.
1037 @param FindInForm Whether find menu in current form or beyond.
1039 @return The row distance from current MenuOption to next selectable MenuOption.
1041 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
1042 @retval Value Find the selectable menu, maybe the truly selectable, maybe the
1043 first menu showing beyond current form or last menu showing in
1045 The value is the line number between the new selected menu and the
1046 current select menu, not include the new selected menu.
1050 MoveToNextStatement (
1052 IN OUT LIST_ENTRY
**CurrentPosition
,
1054 IN BOOLEAN FindInForm
1059 UI_MENU_OPTION
*NextMenuOption
;
1060 UI_MENU_OPTION
*PreMenuOption
;
1063 Pos
= *CurrentPosition
;
1065 if (Pos
== &gMenuOption
) {
1069 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1072 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1074 // NextMenuOption->Row == 0 means this menu has not calculate
1075 // the NextMenuOption->Skip value yet, just calculate here.
1077 if (NextMenuOption
->Row
== 0) {
1078 UpdateOptionSkipLines (NextMenuOption
);
1082 // Check whether the menu is beyond current showing form,
1083 // return the first one beyond the showing form.
1085 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1087 NextMenuOption
= PreMenuOption
;
1093 // return the selectable menu in the showing form.
1095 if (IsSelectable (NextMenuOption
)) {
1099 Distance
+= NextMenuOption
->Skip
;
1102 // Arrive at begin of the menu list.
1104 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1109 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1110 PreMenuOption
= NextMenuOption
;
1113 *CurrentPosition
= &NextMenuOption
->Link
;
1119 Process option string for date/time opcode.
1121 @param MenuOption Menu option point to date/time.
1122 @param OptionString Option string input for process.
1123 @param AddOptCol Whether need to update MenuOption->OptCol.
1127 ProcessStringForDateTime (
1128 UI_MENU_OPTION
*MenuOption
,
1129 CHAR16
*OptionString
,
1135 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1139 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
1141 Statement
= MenuOption
->ThisTag
;
1144 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1145 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
1146 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1147 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
1151 // If leading spaces on OptionString - remove the spaces
1153 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1155 // Base on the blockspace to get the option column info.
1158 MenuOption
->OptCol
++;
1162 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1163 OptionString
[Count
] = OptionString
[Index
];
1166 OptionString
[Count
] = CHAR_NULL
;
1169 // Enable to suppress field in the opcode base on the flag.
1171 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1173 // OptionString format is: <**: **: ****>
1177 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1179 // At this point, only "<**:" in the optionstring.
1180 // Clean the day's ** field, after clean, the format is "< :"
1182 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1183 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1185 // At this point, only "**:" in the optionstring.
1186 // Clean the month's "**" field, after clean, the format is " :"
1188 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1189 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1191 // At this point, only "****>" in the optionstring.
1192 // Clean the year's "****" field, after clean, the format is " >"
1194 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1196 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1198 // OptionString format is: <**: **: **>
1199 // |hour|minute|second|
1202 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1204 // At this point, only "<**:" in the optionstring.
1205 // Clean the hour's ** field, after clean, the format is "< :"
1207 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1208 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1210 // At this point, only "**:" in the optionstring.
1211 // Clean the minute's "**" field, after clean, the format is " :"
1213 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1214 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1216 // At this point, only "**>" in the optionstring.
1217 // Clean the second's "**" field, after clean, the format is " >"
1219 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1226 Adjust Data and Time position accordingly.
1227 Data format : [01/02/2004] [11:22:33]
1228 Line number : 0 0 1 0 0 1
1230 This is an internal function.
1232 @param DirectionUp the up or down direction. False is down. True is
1234 @param CurrentPosition Current position. On return: Point to the last
1235 Option (Year or Second) if up; Point to the first
1236 Option (Month or Hour) if down.
1238 @return Return line number to pad. It is possible that we stand on a zero-advance
1239 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1243 AdjustDateAndTimePosition (
1244 IN BOOLEAN DirectionUp
,
1245 IN OUT LIST_ENTRY
**CurrentPosition
1249 LIST_ENTRY
*NewPosition
;
1250 UI_MENU_OPTION
*MenuOption
;
1251 UINTN PadLineNumber
;
1254 NewPosition
= *CurrentPosition
;
1255 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1257 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1258 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1260 // Calculate the distance from current position to the last Date/Time MenuOption
1263 while (MenuOption
->Skip
== 0) {
1265 NewPosition
= NewPosition
->ForwardLink
;
1266 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1270 NewPosition
= *CurrentPosition
;
1273 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1274 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1275 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1276 // checking can be done.
1278 while (Count
++ < 2) {
1279 NewPosition
= NewPosition
->BackLink
;
1283 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1284 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1285 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1286 // checking can be done.
1288 while (Count
-- > 0) {
1289 NewPosition
= NewPosition
->ForwardLink
;
1293 *CurrentPosition
= NewPosition
;
1296 return PadLineNumber
;
1300 Get step info from numeric opcode.
1302 @param[in] OpCode The input numeric op code.
1304 @return step info for this opcode.
1308 IN EFI_IFR_OP_HEADER
*OpCode
1311 EFI_IFR_NUMERIC
*NumericOp
;
1314 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1316 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1317 case EFI_IFR_NUMERIC_SIZE_1
:
1318 Step
= NumericOp
->data
.u8
.Step
;
1321 case EFI_IFR_NUMERIC_SIZE_2
:
1322 Step
= NumericOp
->data
.u16
.Step
;
1325 case EFI_IFR_NUMERIC_SIZE_4
:
1326 Step
= NumericOp
->data
.u32
.Step
;
1329 case EFI_IFR_NUMERIC_SIZE_8
:
1330 Step
= NumericOp
->data
.u64
.Step
;
1342 Find the registered HotKey based on KeyData.
1344 @param[in] KeyData A pointer to a buffer that describes the keystroke
1345 information for the hot key.
1347 @return The registered HotKey context. If no found, NULL will return.
1350 GetHotKeyFromRegisterList (
1351 IN EFI_INPUT_KEY
*KeyData
1355 BROWSER_HOT_KEY
*HotKey
;
1357 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1358 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1359 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1361 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1365 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1373 Determine if the menu is the last menu that can be selected.
1375 This is an internal function.
1377 @param Direction The scroll direction. False is down. True is up.
1378 @param CurrentPos The current focus.
1380 @return FALSE -- the menu isn't the last menu that can be selected.
1381 @return TRUE -- the menu is the last menu that can be selected.
1386 IN BOOLEAN Direction
,
1387 IN LIST_ENTRY
*CurrentPos
1392 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1394 if (Temp
== &gMenuOption
) {
1402 Wait for a given event to fire, or for an optional timeout to expire.
1404 @param Event The event to wait for
1406 @retval UI_EVENT_TYPE The type of the event which is trigged.
1418 EFI_EVENT TimerEvent
;
1419 EFI_EVENT WaitList
[3];
1420 UI_EVENT_TYPE EventType
;
1423 Timeout
= FormExitTimeout(gFormData
);
1426 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1429 // Set the timer event
1438 WaitList
[0] = Event
;
1440 if (gFormData
->FormRefreshEvent
!= NULL
) {
1441 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1446 WaitList
[EventNum
] = TimerEvent
;
1450 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1451 ASSERT_EFI_ERROR (Status
);
1455 EventType
= UIEventKey
;
1459 if (gFormData
->FormRefreshEvent
!= NULL
) {
1460 EventType
= UIEventDriver
;
1462 ASSERT (Timeout
!= 0 && EventNum
== 2);
1463 EventType
= UIEventTimeOut
;
1468 ASSERT (Index
== 2 && EventNum
== 3);
1469 EventType
= UIEventTimeOut
;
1474 gBS
->CloseEvent (TimerEvent
);
1481 Get question id info from the input opcode header.
1483 @param OpCode The input opcode header pointer.
1485 @retval The question id for this opcode.
1490 IN EFI_IFR_OP_HEADER
*OpCode
1493 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1495 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1499 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1501 return QuestionHeader
->QuestionId
;
1506 Find the top of screen menu base on the current menu.
1508 @param CurPos Current input menu.
1509 @param Rows Totol screen rows.
1510 @param SkipValue SkipValue for this new form.
1512 @retval TopOfScreen Top of screen menu for the new form.
1516 FindTopOfScreenMenu (
1517 IN LIST_ENTRY
*CurPos
,
1519 OUT UINTN
*SkipValue
1523 LIST_ENTRY
*TopOfScreen
;
1524 UI_MENU_OPTION
*PreviousMenuOption
;
1527 PreviousMenuOption
= NULL
;
1529 while (Link
->BackLink
!= &gMenuOption
) {
1530 Link
= Link
->BackLink
;
1531 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1532 if (PreviousMenuOption
->Row
== 0) {
1533 UpdateOptionSkipLines (PreviousMenuOption
);
1535 if (Rows
<= PreviousMenuOption
->Skip
) {
1538 Rows
= Rows
- PreviousMenuOption
->Skip
;
1541 if (Link
->BackLink
== &gMenuOption
) {
1542 TopOfScreen
= gMenuOption
.ForwardLink
;
1543 if (PreviousMenuOption
!= NULL
&& Rows
< PreviousMenuOption
->Skip
) {
1544 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1550 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1557 Get the index info for this opcode.
1559 @param OpCode The input opcode for the statement.
1561 @retval The index of this statement.
1565 GetIndexInfoForOpcode (
1566 IN EFI_IFR_OP_HEADER
*OpCode
1570 UI_MENU_OPTION
*MenuOption
;
1573 NewPos
= gMenuOption
.ForwardLink
;
1576 for (NewPos
= gMenuOption
.ForwardLink
; NewPos
!= &gMenuOption
; NewPos
= NewPos
->ForwardLink
){
1577 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1579 if (CompareMem (MenuOption
->ThisTag
->OpCode
, OpCode
, OpCode
->Length
) == 0) {
1580 if (MenuOption
->ThisTag
->OpCode
== OpCode
) {
1592 Is this the saved highlight statement.
1594 @param HighLightedStatement The input highlight statement.
1596 @retval TRUE This is the highlight statement.
1597 @retval FALSE This is not the highlight statement.
1601 IsSavedHighlightStatement (
1602 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1605 if ((gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
) &&
1606 (gFormData
->FormId
== gHighligthMenuInfo
.FormId
)) {
1607 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1608 return (BOOLEAN
) (gHighligthMenuInfo
.HLTQuestionId
== GetQuestionIdInfo (HighLightedStatement
->OpCode
));
1610 if (CompareMem (gHighligthMenuInfo
.HLTOpCode
, HighLightedStatement
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1611 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(HighLightedStatement
->OpCode
)) {
1624 Is this the highlight menu.
1626 @param MenuOption The input Menu option.
1628 @retval TRUE This is the highlight menu option.
1629 @retval FALSE This is not the highlight menu option.
1633 IsHighLightMenuOption (
1634 IN UI_MENU_OPTION
*MenuOption
1637 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1638 if (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.HLTQuestionId
) {
1639 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1642 if(CompareMem (gHighligthMenuInfo
.HLTOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1643 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1644 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1655 Find the highlight menu.
1657 If the input is NULL, base on the record highlight info in
1658 gHighligthMenuInfo to find the last highlight menu.
1660 @param HighLightedStatement The input highlight statement.
1662 @retval The highlight menu index.
1666 FindHighLightMenuOption (
1667 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1671 UI_MENU_OPTION
*MenuOption
;
1673 NewPos
= gMenuOption
.ForwardLink
;
1674 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1676 if (HighLightedStatement
!= NULL
) {
1677 while (MenuOption
->ThisTag
!= HighLightedStatement
) {
1678 NewPos
= NewPos
->ForwardLink
;
1679 if (NewPos
== &gMenuOption
) {
1681 // Not Found it, break
1685 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1689 // Must find the highlight statement.
1691 ASSERT (NewPos
!= &gMenuOption
);
1694 while (!IsHighLightMenuOption (MenuOption
)) {
1695 NewPos
= NewPos
->ForwardLink
;
1696 if (NewPos
== &gMenuOption
) {
1698 // Not Found it, break
1702 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1706 // Highlight statement has disappear (suppressed/disableed)
1708 if (NewPos
== &gMenuOption
) {
1717 Is this the Top of screen menu.
1719 @param MenuOption The input Menu option.
1721 @retval TRUE This is the Top of screen menu option.
1722 @retval FALSE This is not the Top of screen menu option.
1726 IsTopOfScreeMenuOption (
1727 IN UI_MENU_OPTION
*MenuOption
1730 if (gHighligthMenuInfo
.TOSQuestionId
!= 0) {
1731 return (BOOLEAN
) (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.TOSQuestionId
);
1734 if(CompareMem (gHighligthMenuInfo
.TOSOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.TOSOpCode
->Length
) == 0) {
1735 if (gHighligthMenuInfo
.TOSIndex
== 0 || gHighligthMenuInfo
.TOSIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1746 Calculate the distance between two menus and include the skip value of StartMenu.
1748 @param StartMenu The link_entry pointer to start menu.
1749 @param EndMenu The link_entry pointer to end menu.
1753 GetDistanceBetweenMenus(
1754 IN LIST_ENTRY
*StartMenu
,
1755 IN LIST_ENTRY
*EndMenu
1759 UI_MENU_OPTION
*MenuOption
;
1765 while (Link
!= EndMenu
) {
1766 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1767 if (MenuOption
->Row
== 0) {
1768 UpdateOptionSkipLines (MenuOption
);
1770 Distance
+= MenuOption
->Skip
;
1771 Link
= Link
->BackLink
;
1777 Find the top of screen menu base on the previous record menu info.
1779 @param HighLightMenu The link_entry pointer to highlight menu.
1781 @retval Return the the link_entry pointer top of screen menu.
1785 FindTopOfScreenMenuOption (
1786 IN LIST_ENTRY
*HighLightMenu
1790 UI_MENU_OPTION
*MenuOption
;
1794 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1795 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1797 NewPos
= gMenuOption
.ForwardLink
;
1798 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1800 while (!IsTopOfScreeMenuOption(MenuOption
)) {
1801 NewPos
= NewPos
->ForwardLink
;
1802 if (NewPos
== &gMenuOption
) {
1804 // Not Found it, break
1808 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1812 // Last time top of screen menu has disappeared.
1814 if (NewPos
== &gMenuOption
) {
1818 // Check whether highlight menu and top of screen menu can be shown within one page,
1819 // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
1820 // may be dynamically inserted between highlightmenu and previous top of screen menu,
1821 // So previous record top of screen menu is not appropriate for current display.
1823 if (GetDistanceBetweenMenus (HighLightMenu
, NewPos
) + 1 > BottomRow
- TopRow
) {
1831 Find the first menu which will be show at the top.
1833 @param FormData The data info for this form.
1834 @param TopOfScreen The link_entry pointer to top menu.
1835 @param HighlightMenu The menu which will be highlight.
1836 @param SkipValue The skip value for the top menu.
1841 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1842 OUT LIST_ENTRY
**TopOfScreen
,
1843 OUT LIST_ENTRY
**HighlightMenu
,
1844 OUT UINTN
*SkipValue
1849 UI_MENU_OPTION
*MenuOption
;
1852 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1853 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1855 // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
1856 // and the other is exit current form and enter last form, it can be covered by the else case.
1858 if (gMisMatch
&& gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
&& gFormData
->FormId
== gHighligthMenuInfo
.FormId
) {
1860 // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
1861 // base on the record highlight info to find the highlight menu.
1864 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1865 if (*HighlightMenu
!= NULL
) {
1867 // Update skip info for this highlight menu.
1869 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1870 UpdateOptionSkipLines (MenuOption
);
1873 // Found the last time highlight menu.
1875 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1876 if (*TopOfScreen
!= NULL
) {
1878 // Found the last time selectable top of screen menu.
1880 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1881 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1882 UpdateOptionSkipLines (MenuOption
);
1884 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1887 // Not found last time top of screen menu, so base on current highlight menu
1888 // to find the new top of screen menu.
1889 // Make the current highlight menu at the bottom of the form to calculate the
1890 // top of screen menu.
1892 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1893 *TopOfScreen
= *HighlightMenu
;
1896 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1899 *SkipValue
= TmpValue
;
1903 // Last time highlight menu has disappear, find the first highlightable menu as the default one.
1905 *HighlightMenu
= gMenuOption
.ForwardLink
;
1906 if (!IsListEmpty (&gMenuOption
)) {
1907 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1909 *TopOfScreen
= gMenuOption
.ForwardLink
;
1913 } else if (FormData
->HighLightedStatement
!= NULL
) {
1914 if (IsSavedHighlightStatement (FormData
->HighLightedStatement
)) {
1916 // Input highlight menu is same as last time highlight menu.
1917 // Base on last time highlight menu to set the top of screen menu and highlight menu.
1919 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1920 ASSERT (*HighlightMenu
!= NULL
);
1923 // Update skip info for this highlight menu.
1925 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1926 UpdateOptionSkipLines (MenuOption
);
1928 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1929 if (*TopOfScreen
== NULL
) {
1931 // Not found last time top of screen menu, so base on current highlight menu
1932 // to find the new top of screen menu.
1933 // Make the current highlight menu at the bottom of the form to calculate the
1934 // top of screen menu.
1936 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1937 *TopOfScreen
= *HighlightMenu
;
1940 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1943 *SkipValue
= TmpValue
;
1945 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1946 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1947 UpdateOptionSkipLines (MenuOption
);
1949 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1951 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1954 // Input highlight menu is not save as last time highlight menu.
1956 *HighlightMenu
= FindHighLightMenuOption(FormData
->HighLightedStatement
);
1957 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1958 UpdateOptionSkipLines (MenuOption
);
1961 // Make the current highlight menu at the bottom of the form to calculate the
1962 // top of screen menu.
1964 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1965 *TopOfScreen
= *HighlightMenu
;
1968 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1971 *SkipValue
= TmpValue
;
1973 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1976 // If not has input highlight statement, just return the first one in this form.
1978 *TopOfScreen
= gMenuOption
.ForwardLink
;
1979 *HighlightMenu
= gMenuOption
.ForwardLink
;
1980 if (!IsListEmpty (&gMenuOption
)) {
1981 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1989 // First enter to show the menu, update highlight info.
1991 UpdateHighlightMenuInfo (*HighlightMenu
, *TopOfScreen
, *SkipValue
);
1995 Record the highlight menu and top of screen menu info.
1997 @param Highlight The menu opton which is highlight.
1998 @param TopOfScreen The menu opton which is at the top of the form.
1999 @param SkipValue The skip line info for the top of screen menu.
2003 UpdateHighlightMenuInfo (
2004 IN LIST_ENTRY
*Highlight
,
2005 IN LIST_ENTRY
*TopOfScreen
,
2009 UI_MENU_OPTION
*MenuOption
;
2010 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2012 gHighligthMenuInfo
.HiiHandle
= gFormData
->HiiHandle
;
2013 gHighligthMenuInfo
.FormId
= gFormData
->FormId
;
2014 gHighligthMenuInfo
.SkipValue
= (UINT16
)SkipValue
;
2016 if (!IsListEmpty (&gMenuOption
)) {
2017 MenuOption
= MENU_OPTION_FROM_LINK (Highlight
);
2018 Statement
= MenuOption
->ThisTag
;
2020 gUserInput
->SelectedStatement
= Statement
;
2022 gHighligthMenuInfo
.HLTSequence
= MenuOption
->Sequence
;
2023 gHighligthMenuInfo
.HLTQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
2024 if (gHighligthMenuInfo
.HLTQuestionId
== 0) {
2026 // if question id == 0, save the opcode buffer..
2028 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2029 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2031 gHighligthMenuInfo
.HLTOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2032 ASSERT (gHighligthMenuInfo
.HLTOpCode
!= NULL
);
2034 gHighligthMenuInfo
.HLTIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2037 MenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2038 Statement
= MenuOption
->ThisTag
;
2040 gHighligthMenuInfo
.TOSQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
2041 if (gHighligthMenuInfo
.TOSQuestionId
== 0) {
2043 // if question id == 0, save the opcode buffer..
2045 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2046 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2048 gHighligthMenuInfo
.TOSOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2049 ASSERT (gHighligthMenuInfo
.TOSOpCode
!= NULL
);
2051 gHighligthMenuInfo
.TOSIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2054 gUserInput
->SelectedStatement
= NULL
;
2056 gHighligthMenuInfo
.HLTSequence
= 0;
2057 gHighligthMenuInfo
.HLTQuestionId
= 0;
2058 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2059 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2061 gHighligthMenuInfo
.HLTOpCode
= NULL
;
2062 gHighligthMenuInfo
.HLTIndex
= 0;
2064 gHighligthMenuInfo
.TOSQuestionId
= 0;
2065 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2066 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2068 gHighligthMenuInfo
.TOSOpCode
= NULL
;
2069 gHighligthMenuInfo
.TOSIndex
= 0;
2074 Update attribut for this menu.
2076 @param MenuOption The menu opton which this attribut used to.
2077 @param Highlight Whether this menu will be highlight.
2081 SetDisplayAttribute (
2082 IN UI_MENU_OPTION
*MenuOption
,
2083 IN BOOLEAN Highlight
2086 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2088 Statement
= MenuOption
->ThisTag
;
2091 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2095 if (MenuOption
->GrayOut
) {
2096 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2098 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2099 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2101 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2107 Print string for this menu option.
2109 @param MenuOption The menu opton which this attribut used to.
2110 @param Col The column that this string will be print at.
2111 @param Row The row that this string will be print at.
2112 @param String The string which need to print.
2113 @param Width The width need to print, if string is less than the
2114 width, the block space will be used.
2115 @param Highlight Whether this menu will be highlight.
2120 IN UI_MENU_OPTION
*MenuOption
,
2125 IN BOOLEAN Highlight
2131 // Print string with normal color.
2134 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
2139 // Print the highlight menu string.
2140 // First print the highlight string.
2142 SetDisplayAttribute(MenuOption
, TRUE
);
2143 Length
= PrintStringAt (Col
, Row
, String
);
2146 // Second, clean the empty after the string.
2148 SetDisplayAttribute(MenuOption
, FALSE
);
2149 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
2153 Check whether this menu can has option string.
2155 @param MenuOption The menu opton which this attribut used to.
2157 @retval TRUE This menu option can have option string.
2158 @retval FALSE This menu option can't have option string.
2163 IN UI_MENU_OPTION
*MenuOption
2166 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2169 EFI_IFR_TEXT
*TextOp
;
2172 Statement
= MenuOption
->ThisTag
;
2175 // See if the second text parameter is really NULL
2177 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2178 TextOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
2179 if (TextOp
->TextTwo
!= 0) {
2180 String
= GetToken (TextOp
->TextTwo
, gFormData
->HiiHandle
);
2181 Size
= StrLen (String
);
2186 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
2187 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
2188 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
2189 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
2190 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
2192 // Allow a wide display if text op-code and no secondary text op-code
2194 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
2204 Double confirm with user about the action.
2206 @param Action The user input action.
2208 @retval TRUE User confirm with the input or not need user confirm.
2209 @retval FALSE User want ignore this input.
2226 CatLen
= StrLen (gConfirmMsgConnect
);
2229 // Below action need extra popup dialog to confirm.
2231 CheckFlags
= BROWSER_ACTION_DISCARD
|
2232 BROWSER_ACTION_DEFAULT
|
2233 BROWSER_ACTION_SUBMIT
|
2234 BROWSER_ACTION_RESET
|
2235 BROWSER_ACTION_EXIT
;
2238 // Not need to confirm with user, just return TRUE.
2240 if ((Action
& CheckFlags
) == 0) {
2244 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2245 CfmStrLen
+= StrLen (gConfirmDiscardMsg
);
2248 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2249 if (CfmStrLen
!= 0) {
2250 CfmStrLen
+= CatLen
;
2253 CfmStrLen
+= StrLen (gConfirmDefaultMsg
);
2256 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2257 if (CfmStrLen
!= 0) {
2258 CfmStrLen
+= CatLen
;
2261 CfmStrLen
+= StrLen (gConfirmSubmitMsg
);
2264 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2265 if (CfmStrLen
!= 0) {
2266 CfmStrLen
+= CatLen
;
2269 CfmStrLen
+= StrLen (gConfirmResetMsg
);
2272 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2273 if (CfmStrLen
!= 0) {
2274 CfmStrLen
+= CatLen
;
2277 CfmStrLen
+= StrLen (gConfirmExitMsg
);
2281 // Allocate buffer to save the string.
2282 // String + "?" + "\0"
2284 MaxLen
= CfmStrLen
+ 1 + 1;
2285 CfmStr
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
2286 ASSERT (CfmStr
!= NULL
);
2288 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2289 StrCpyS (CfmStr
, MaxLen
, gConfirmDiscardMsg
);
2292 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2293 if (CfmStr
[0] != 0) {
2294 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2295 StrCatS (CfmStr
, MaxLen
, gConfirmDefaultMsg2nd
);
2297 StrCpyS (CfmStr
, MaxLen
, gConfirmDefaultMsg
);
2301 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2302 if (CfmStr
[0] != 0) {
2303 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2304 StrCatS (CfmStr
, MaxLen
, gConfirmSubmitMsg2nd
);
2306 StrCpyS (CfmStr
, MaxLen
, gConfirmSubmitMsg
);
2310 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2311 if (CfmStr
[0] != 0) {
2312 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2313 StrCatS (CfmStr
, MaxLen
, gConfirmResetMsg2nd
);
2315 StrCpyS (CfmStr
, MaxLen
, gConfirmResetMsg
);
2319 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2320 if (CfmStr
[0] != 0) {
2321 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2322 StrCatS (CfmStr
, MaxLen
, gConfirmExitMsg2nd
);
2324 StrCpyS (CfmStr
, MaxLen
, gConfirmExitMsg
);
2328 StrCatS (CfmStr
, MaxLen
, gConfirmMsgEnd
);
2331 CreateDialog (&Key
, gEmptyString
, CfmStr
, gConfirmOpt
, gEmptyString
, NULL
);
2332 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2333 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptNo
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2334 (Key
.ScanCode
!= SCAN_ESC
));
2336 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) {
2348 Print string for this menu option.
2350 @param MenuOption The menu opton which this attribut used to.
2351 @param SkipWidth The skip width between the left to the start of the prompt.
2352 @param BeginCol The begin column for one menu.
2353 @param SkipLine The skip line for this menu.
2354 @param BottomRow The bottom row for this form.
2355 @param Highlight Whether this menu will be highlight.
2356 @param UpdateCol Whether need to update the column info for Date/Time.
2358 @retval EFI_SUCESSS Process the user selection success.
2363 IN UI_MENU_OPTION
*MenuOption
,
2368 IN BOOLEAN Highlight
,
2369 IN BOOLEAN UpdateCol
2372 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2377 CHAR16
*OptionString
;
2378 CHAR16
*OutputString
;
2385 BOOLEAN IsProcessingFirstRow
;
2387 UINTN PromptLineNum
;
2388 UINTN OptionLineNum
;
2392 Statement
= MenuOption
->ThisTag
;
2400 IsProcessingFirstRow
= TRUE
;
2403 // Set default color.
2405 SetDisplayAttribute (MenuOption
, FALSE
);
2408 // 1. Paint the option string.
2410 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
2411 if (EFI_ERROR (Status
)) {
2415 if (OptionString
!= NULL
) {
2416 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2418 // Adjust option string for date/time opcode.
2420 ProcessStringForDateTime(MenuOption
, OptionString
, UpdateCol
);
2423 Width
= (UINT16
) gOptionBlockWidth
- 1;
2424 Row
= MenuOption
->Row
;
2428 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2429 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
2430 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2432 // For date/time question, it has three menu options for this qustion.
2433 // The first/second menu options with the skip value is 0. the last one
2434 // with skip value is 1.
2436 if (MenuOption
->Skip
!= 0) {
2438 // For date/ time, print the last past (year for date and second for time)
2439 // - 7 means skip [##/##/ for date and [##:##: for time.
2441 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
2444 // For date/ time, print the first and second past (year for date and second for time)
2445 // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
2446 // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
2447 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
) - 1, Highlight
);
2450 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2456 // If there is more string to process print on the next row and increment the Skip value
2458 if (StrLen (&OptionString
[Index
]) != 0) {
2462 // Since the Number of lines for this menu entry may or may not be reflected accurately
2463 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2464 // some testing to ensure we are keeping this in-sync.
2466 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2468 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2474 FreePool (OutputString
);
2482 FreePool (OptionString
);
2486 // 2. Paint the description.
2488 PromptWidth
= GetWidth (MenuOption
, &AdjustValue
);
2489 Row
= MenuOption
->Row
;
2493 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
2494 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
2497 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2498 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2500 // 1.Clean the start LEFT_SKIPPED_COLUMNS
2502 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
2504 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2 && IsProcessingFirstRow
) {
2506 // Print Arrow for Goto button.
2509 MenuOption
->Col
- 2,
2511 GEOMETRICSHAPE_RIGHT_TRIANGLE
2513 IsProcessingFirstRow
= FALSE
;
2515 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
2519 // If there is more string to process print on the next row and increment the Skip value
2521 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2527 FreePool (OutputString
);
2538 // 3. If this is a text op with secondary text information
2540 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
2541 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
2543 Width
= (UINT16
) gOptionBlockWidth
- 1;
2544 Row
= MenuOption
->Row
;
2548 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2549 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
2550 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2554 // If there is more string to process print on the next row and increment the Skip value
2556 if (StrLen (&StringPtr
[Index
]) != 0) {
2560 // If the rows for text two is greater than or equal to the skip value, increase the skip value
2562 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2568 FreePool (OutputString
);
2574 FreePool (StringPtr
);
2578 // 4.Line number for Option string and prompt string are not equal.
2579 // Clean the column whose line number is less.
2581 if (HasOptionString(MenuOption
) && (OptionLineNum
!= PromptLineNum
)) {
2582 Col
= OptionLineNum
< PromptLineNum
? MenuOption
->OptCol
: BeginCol
;
2583 Row
= (OptionLineNum
< PromptLineNum
? OptionLineNum
: PromptLineNum
) + MenuOption
->Row
;
2584 Width
= (UINT16
) (OptionLineNum
< PromptLineNum
? gOptionBlockWidth
: PromptWidth
+ AdjustValue
+ SkipWidth
);
2585 MaxRow
= (OptionLineNum
< PromptLineNum
? PromptLineNum
: OptionLineNum
) + MenuOption
->Row
- 1;
2587 while (Row
<= MaxRow
) {
2588 DisplayMenuString (MenuOption
, Col
, Row
++, L
"", Width
, FALSE
);
2596 Display menu and wait for user to select one menu option, then return it.
2597 If AutoBoot is enabled, then if user doesn't select any option,
2598 after period of time, it will automatically return the first menu option.
2600 @param FormData The current form data info.
2602 @retval EFI_SUCESSS Process the user selection success.
2603 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
2608 IN FORM_DISPLAY_ENGINE_FORM
*FormData
2613 UINTN DistanceValue
;
2622 CHAR16
*StringRightPtr
;
2623 CHAR16
*StringErrorPtr
;
2624 CHAR16
*OptionString
;
2626 CHAR16
*HelpHeaderString
;
2627 CHAR16
*HelpBottomString
;
2636 LIST_ENTRY
*TopOfScreen
;
2637 LIST_ENTRY
*SavedListEntry
;
2638 UI_MENU_OPTION
*MenuOption
;
2639 UI_MENU_OPTION
*NextMenuOption
;
2640 UI_MENU_OPTION
*SavedMenuOption
;
2641 UI_CONTROL_FLAG ControlFlag
;
2642 UI_SCREEN_OPERATION ScreenOperation
;
2643 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2644 BROWSER_HOT_KEY
*HotKey
;
2645 UINTN HelpPageIndex
;
2646 UINTN HelpPageCount
;
2649 UINTN HelpHeaderLine
;
2650 UINTN HelpBottomLine
;
2651 BOOLEAN MultiHelpPage
;
2652 UINT16 EachLineWidth
;
2653 UINT16 HeaderLineWidth
;
2654 UINT16 BottomLineWidth
;
2655 EFI_STRING_ID HelpInfo
;
2656 UI_EVENT_TYPE EventType
;
2657 BOOLEAN SkipHighLight
;
2658 EFI_HII_VALUE
*StatementValue
;
2660 EventType
= UIEventNone
;
2661 Status
= EFI_SUCCESS
;
2663 HelpHeaderString
= NULL
;
2664 HelpBottomString
= NULL
;
2665 OptionString
= NULL
;
2666 ScreenOperation
= UiNoOperation
;
2674 MultiHelpPage
= FALSE
;
2676 HeaderLineWidth
= 0;
2677 BottomLineWidth
= 0;
2681 SkipHighLight
= FALSE
;
2683 NextMenuOption
= NULL
;
2684 SavedMenuOption
= NULL
;
2688 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
2690 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2692 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
2693 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
2696 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2697 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
2699 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2702 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
2703 if (!IsListEmpty (&gMenuOption
)) {
2704 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2705 gUserInput
->SelectedStatement
= NextMenuOption
->ThisTag
;
2708 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2710 ControlFlag
= CfInitialization
;
2712 switch (ControlFlag
) {
2713 case CfInitialization
:
2714 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
2715 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
2717 // Clear Statement range if different formset is painted.
2720 gStatementDimensions
.LeftColumn
,
2721 gStatementDimensions
.RightColumn
,
2722 TopRow
- SCROLL_ARROW_HEIGHT
,
2723 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2724 GetFieldTextColor ()
2728 ControlFlag
= CfRepaint
;
2732 ControlFlag
= CfRefreshHighLight
;
2742 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2745 // 1. Check whether need to print the arrow up.
2747 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2751 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2752 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2754 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2757 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2759 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2760 TopRow
- SCROLL_ARROW_HEIGHT
,
2763 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2767 // 2.Paint the menu.
2769 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2770 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2771 MenuOption
->Row
= Row
;
2772 MenuOption
->Col
= Col
;
2773 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2774 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2776 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2779 if (MenuOption
->NestInStatement
) {
2780 MenuOption
->Col
+= SUBTITLE_INDENT
;
2784 // Save the highlight menu, will be used in CfRefreshHighLight case.
2786 if (Link
== NewPos
) {
2787 SavedMenuOption
= MenuOption
;
2788 SkipHighLight
= TRUE
;
2791 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2792 Status
= DisplayOneMenu (MenuOption
,
2793 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2794 gStatementDimensions
.LeftColumn
+ gModalSkipColumn
,
2795 Link
== TopOfScreen
? SkipValue
: 0,
2797 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2801 Status
= DisplayOneMenu (MenuOption
,
2802 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2803 gStatementDimensions
.LeftColumn
,
2804 Link
== TopOfScreen
? SkipValue
: 0,
2806 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2811 if (EFI_ERROR (Status
)) {
2819 // 3. Update the row info which will be used by next menu.
2821 if (Link
== TopOfScreen
) {
2822 Row
+= MenuOption
->Skip
- SkipValue
;
2824 Row
+= MenuOption
->Skip
;
2827 if (Row
> BottomRow
) {
2828 if (!ValueIsScroll (FALSE
, Link
)) {
2832 Row
= BottomRow
+ 1;
2838 // 3. Menus in this form may not cover all form, clean the remain field.
2840 while (Row
<= BottomRow
) {
2841 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2842 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2844 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2849 // 4. Print the down arrow row.
2851 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2852 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * + gModalSkipColumn
);
2854 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2857 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2859 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2860 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2863 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2870 case CfRefreshHighLight
:
2873 // MenuOption: Last menu option that need to remove hilight
2874 // MenuOption is set to NULL in Repaint
2875 // NewPos: Current menu option that need to hilight
2877 ControlFlag
= CfUpdateHelpString
;
2879 ASSERT (NewPos
!= NULL
);
2880 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
2882 if (SkipHighLight
) {
2883 SkipHighLight
= FALSE
;
2884 MenuOption
= SavedMenuOption
;
2885 RefreshKeyHelp(gFormData
, SavedMenuOption
->ThisTag
, FALSE
);
2889 if (IsListEmpty (&gMenuOption
)) {
2891 // No menu option, just update the hotkey filed.
2893 RefreshKeyHelp(gFormData
, NULL
, FALSE
);
2897 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2902 if (NewPos
== TopOfScreen
) {
2908 if (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
) {
2909 if (MenuOption
!= NULL
) {
2911 // Remove the old highlight menu.
2913 Status
= DisplayOneMenu (MenuOption
,
2914 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2915 gStatementDimensions
.LeftColumn
,
2924 // This is the current selected statement
2926 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2927 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2929 if (!IsSelectable (MenuOption
)) {
2933 Status
= DisplayOneMenu (MenuOption
,
2934 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2935 gStatementDimensions
.LeftColumn
,
2944 case CfUpdateHelpString
:
2945 ControlFlag
= CfPrepareToReadKey
;
2946 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2951 // NewLine means only update highlight menu (remove old highlight and highlith
2952 // the new one), not need to full repain the form.
2954 if (Repaint
|| NewLine
) {
2955 if (IsListEmpty (&gMenuOption
)) {
2957 // Don't print anything if no mwnu option.
2959 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2962 // Don't print anything if it is a NULL help token
2964 ASSERT(MenuOption
!= NULL
);
2965 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2966 Statement
= MenuOption
->ThisTag
;
2967 StatementValue
= &Statement
->CurrentValue
;
2968 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2969 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)){
2970 StringPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2972 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2975 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)){
2976 StringRightPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2977 StringErrorPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2978 StringPtr
= AllocateZeroPool ((StrLen (StringRightPtr
) + StrLen (StringErrorPtr
)+ 1 ) * sizeof (CHAR16
));
2979 StrCpyS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringRightPtr
);
2980 StrCatS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringErrorPtr
);
2981 FreePool (StringRightPtr
);
2982 FreePool (StringErrorPtr
);
2984 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2989 RowCount
= BottomRow
- TopRow
+ 1;
2992 // 1.Calculate how many line the help string need to print.
2994 if (HelpString
!= NULL
) {
2995 FreePool (HelpString
);
2998 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2999 FreePool (StringPtr
);
3001 if (HelpLine
> RowCount
) {
3002 MultiHelpPage
= TRUE
;
3003 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
3004 if (HelpHeaderString
!= NULL
) {
3005 FreePool (HelpHeaderString
);
3006 HelpHeaderString
= NULL
;
3008 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
3009 FreePool (StringPtr
);
3010 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
3011 if (HelpBottomString
!= NULL
) {
3012 FreePool (HelpBottomString
);
3013 HelpBottomString
= NULL
;
3015 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
3016 FreePool (StringPtr
);
3018 // Calculate the help page count.
3020 if (HelpLine
> 2 * RowCount
- 2) {
3021 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
3022 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) != 0) {
3029 MultiHelpPage
= FALSE
;
3034 // Check whether need to show the 'More(U/u)' at the begin.
3035 // Base on current direct info, here shows aligned to the right side of the column.
3036 // If the direction is multi line and aligned to right side may have problem, so
3037 // add ASSERT code here.
3039 if (HelpPageIndex
> 0) {
3040 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3041 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
3042 ASSERT (HelpHeaderLine
== 1);
3043 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3044 PrintStringAtWithWidth (
3045 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3051 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
3053 &HelpHeaderString
[Index
* HeaderLineWidth
]
3058 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
3060 // Print the help string info.
3062 if (!MultiHelpPage
) {
3063 for (Index
= 0; Index
< HelpLine
; Index
++) {
3064 PrintStringAtWithWidth (
3065 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3067 &HelpString
[Index
* EachLineWidth
],
3071 for (; Index
< RowCount
; Index
++) {
3072 PrintStringAtWithWidth (
3073 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3079 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3081 if (HelpPageIndex
== 0) {
3082 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
3083 PrintStringAtWithWidth (
3084 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3086 &HelpString
[Index
* EachLineWidth
],
3091 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
3092 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
3093 PrintStringAtWithWidth (
3094 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3095 Index
+ TopRow
+ HelpHeaderLine
,
3096 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
3100 if (HelpPageIndex
== HelpPageCount
- 1) {
3101 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
3102 PrintStringAtWithWidth (
3103 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3104 Index
+ TopRow
+ HelpHeaderLine
,
3109 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3115 // Check whether need to print the 'More(D/d)' at the bottom.
3116 // Base on current direct info, here shows aligned to the right side of the column.
3117 // If the direction is multi line and aligned to right side may have problem, so
3118 // add ASSERT code here.
3120 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
3121 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3122 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
3123 ASSERT (HelpBottomLine
== 1);
3124 ASSERT (GetStringWidth (HelpBottomString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3125 PrintStringAtWithWidth (
3126 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3127 BottomRow
+ Index
- HelpBottomLine
+ 1,
3132 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
3133 BottomRow
+ Index
- HelpBottomLine
+ 1,
3134 &HelpBottomString
[Index
* BottomLineWidth
]
3139 // Reset this flag every time we finish using it.
3145 case CfPrepareToReadKey
:
3146 ControlFlag
= CfReadKey
;
3147 ScreenOperation
= UiNoOperation
;
3151 ControlFlag
= CfScreenOperation
;
3154 // Wait for user's selection
3157 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3158 if (!EFI_ERROR (Status
)) {
3159 EventType
= UIEventKey
;
3164 // If we encounter error, continue to read another key in.
3166 if (Status
!= EFI_NOT_READY
) {
3170 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
3171 if (EventType
== UIEventKey
) {
3172 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3177 if (EventType
== UIEventDriver
) {
3179 gUserInput
->Action
= BROWSER_ACTION_NONE
;
3180 ControlFlag
= CfExit
;
3184 if (EventType
== UIEventTimeOut
) {
3185 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3186 ControlFlag
= CfExit
;
3190 switch (Key
.UnicodeChar
) {
3191 case CHAR_CARRIAGE_RETURN
:
3192 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3193 ControlFlag
= CfReadKey
;
3197 ScreenOperation
= UiSelect
;
3202 // We will push the adjustment of these numeric values directly to the input handler
3203 // NOTE: we won't handle manual input numeric
3208 // If the screen has no menu items, and the user didn't select UiReset
3209 // ignore the selection and go back to reading keys.
3211 ASSERT(MenuOption
!= NULL
);
3212 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3213 ControlFlag
= CfReadKey
;
3217 Statement
= MenuOption
->ThisTag
;
3218 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
3219 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3220 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
3222 if (Key
.UnicodeChar
== '+') {
3223 gDirection
= SCAN_RIGHT
;
3225 gDirection
= SCAN_LEFT
;
3228 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3229 if (OptionString
!= NULL
) {
3230 FreePool (OptionString
);
3232 if (EFI_ERROR (Status
)) {
3234 // Repaint to clear possible error prompt pop-up
3239 ControlFlag
= CfExit
;
3245 ScreenOperation
= UiUp
;
3250 ScreenOperation
= UiDown
;
3254 if(IsListEmpty (&gMenuOption
)) {
3255 ControlFlag
= CfReadKey
;
3259 ASSERT(MenuOption
!= NULL
);
3260 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3261 ScreenOperation
= UiSelect
;
3267 if (!MultiHelpPage
) {
3268 ControlFlag
= CfReadKey
;
3271 ControlFlag
= CfUpdateHelpString
;
3272 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3277 if (!MultiHelpPage
) {
3278 ControlFlag
= CfReadKey
;
3281 ControlFlag
= CfUpdateHelpString
;
3282 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3286 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3287 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3288 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3293 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3295 // ModalForm has no ESC key and Hot Key.
3297 ControlFlag
= CfReadKey
;
3298 } else if (Index
== mScanCodeNumber
) {
3300 // Check whether Key matches the registered hot key.
3303 HotKey
= GetHotKeyFromRegisterList (&Key
);
3304 if (HotKey
!= NULL
) {
3305 ScreenOperation
= UiHotKey
;
3312 case CfScreenOperation
:
3313 if ((ScreenOperation
!= UiReset
) && (ScreenOperation
!= UiHotKey
)) {
3315 // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
3316 // ignore the selection and go back to reading keys.
3318 if (IsListEmpty (&gMenuOption
)) {
3319 ControlFlag
= CfReadKey
;
3325 Index
< ARRAY_SIZE (gScreenOperationToControlFlag
);
3328 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3329 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3336 ControlFlag
= CfRepaint
;
3338 ASSERT(MenuOption
!= NULL
);
3339 Statement
= MenuOption
->ThisTag
;
3340 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
3344 switch (Statement
->OpCode
->OpCode
) {
3345 case EFI_IFR_REF_OP
:
3346 case EFI_IFR_ACTION_OP
:
3347 case EFI_IFR_RESET_BUTTON_OP
:
3348 ControlFlag
= CfExit
;
3353 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3355 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
3356 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3358 if (OptionString
!= NULL
) {
3359 FreePool (OptionString
);
3362 if (EFI_ERROR (Status
)) {
3365 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
3368 ControlFlag
= CfExit
;
3376 // We come here when someone press ESC
3377 // If the policy is not exit front page when user press ESC, process here.
3379 if (!FormExitPolicy()) {
3382 ControlFlag
= CfRepaint
;
3386 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3387 ControlFlag
= CfExit
;
3391 ControlFlag
= CfRepaint
;
3393 ASSERT (HotKey
!= NULL
);
3395 if (FxConfirmPopup(HotKey
->Action
)) {
3396 gUserInput
->Action
= HotKey
->Action
;
3397 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3398 gUserInput
->DefaultId
= HotKey
->DefaultId
;
3400 ControlFlag
= CfExit
;
3404 ControlFlag
= CfRepaint
;
3410 ControlFlag
= CfRepaint
;
3411 ASSERT(MenuOption
!= NULL
);
3412 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3413 if (MenuOption
->Sequence
!= 0) {
3415 // In the middle or tail of the Date/Time op-code set, go left.
3417 ASSERT(NewPos
!= NULL
);
3418 NewPos
= NewPos
->BackLink
;
3424 ControlFlag
= CfRepaint
;
3425 ASSERT(MenuOption
!= NULL
);
3426 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3427 if (MenuOption
->Sequence
!= 2) {
3429 // In the middle or tail of the Date/Time op-code set, go left.
3431 ASSERT(NewPos
!= NULL
);
3432 NewPos
= NewPos
->ForwardLink
;
3438 ControlFlag
= CfRepaint
;
3441 SavedListEntry
= NewPos
;
3442 ASSERT(NewPos
!= NULL
);
3444 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3445 ASSERT (MenuOption
!= NULL
);
3448 // Adjust Date/Time position before we advance forward.
3450 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3452 NewPos
= NewPos
->BackLink
;
3454 // Find next selectable menu or the first menu beyond current form.
3456 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
, FALSE
);
3457 if (Difference
< 0) {
3459 // We hit the begining MenuOption that can be focused
3460 // so we simply scroll to the top.
3463 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3464 TopOfScreen
= gMenuOption
.ForwardLink
;
3465 NewPos
= SavedListEntry
;
3469 // Scroll up to the last page when we have arrived at top page.
3471 TopOfScreen
= FindTopOfScreenMenu (gMenuOption
.BackLink
, BottomRow
- TopRow
, &SkipValue
);
3472 NewPos
= gMenuOption
.BackLink
;
3473 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3476 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3478 if (MenuOption
->Row
< TopRow
+ Difference
+ NextMenuOption
->Skip
) {
3480 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3482 TopOfScreen
= NewPos
;
3488 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3490 // BottomRow - TopRow + 1 means the total rows current forms supported.
3491 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3492 // and new top menu. New top menu will all shows in next form, but last highlight menu
3493 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3494 // last highlight menu.
3496 if (!IsSelectable(NextMenuOption
) && IsSelectable(MenuOption
) &&
3497 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3498 NewPos
= SavedListEntry
;
3502 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3505 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3507 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3508 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3510 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3515 // SkipValue means lines is skipped when show the top menu option.
3517 ControlFlag
= CfRepaint
;
3523 // First minus the menu of the top screen, it's value is SkipValue.
3525 if (SkipValue
>= BottomRow
- TopRow
+ 1) {
3527 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
3528 // form of options to be show, so just update the SkipValue to show the next
3529 // parts of options.
3531 SkipValue
-= BottomRow
- TopRow
+ 1;
3532 NewPos
= TopOfScreen
;
3535 Index
= (BottomRow
+ 1) - SkipValue
- TopRow
;
3538 TopOfScreen
= FindTopOfScreenMenu(TopOfScreen
, Index
, &SkipValue
);
3539 NewPos
= TopOfScreen
;
3540 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, FALSE
);
3542 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3545 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3546 // Don't do this when we are already in the first page.
3548 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3549 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3551 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3556 // SkipValue means lines is skipped when show the top menu option.
3558 ControlFlag
= CfRepaint
;
3563 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3564 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
3566 // Count to the menu option which will show at the top of the next form.
3568 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
3569 Link
= Link
->ForwardLink
;
3570 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3571 Index
= Index
+ NextMenuOption
->Skip
;
3574 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
3576 // Highlight on the last menu which can be highlight.
3579 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
, TRUE
);
3582 // Calculate the skip line for top of screen menu.
3584 if (Link
== TopOfScreen
) {
3586 // The top of screen menu option occupies the entire form.
3588 SkipValue
+= BottomRow
- TopRow
+ 1;
3590 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3595 // Move to the Next selectable menu.
3597 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
, TRUE
);
3601 // Save the menu as the next highlight menu.
3605 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3608 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3609 // Don't do this when we are already in the last page.
3611 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3612 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3614 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3619 // SkipValue means lines is skipped when show the top menu option.
3620 // NewPos points to the menu which is highlighted now.
3622 ControlFlag
= CfRepaint
;
3625 if (NewPos
== TopOfScreen
) {
3631 SavedListEntry
= NewPos
;
3633 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3634 // to be one that progresses to the next set of op-codes, we need to advance to the last
3635 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3636 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3637 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3638 // the Date/Time op-code.
3640 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3642 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3643 NewPos
= NewPos
->ForwardLink
;
3645 // Find the next selectable menu.
3647 if (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
> BottomRow
+ 1) {
3648 if (gMenuOption
.ForwardLink
== NewPos
|| &gMenuOption
== NewPos
) {
3654 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
+ 1 - (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
), FALSE
);
3656 if (Difference
< 0) {
3658 // Scroll to the first page.
3660 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3661 TopOfScreen
= gMenuOption
.ForwardLink
;
3665 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3667 NewPos
= gMenuOption
.ForwardLink
;
3668 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3672 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3674 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3675 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3677 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3682 // Get next selected menu info.
3684 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3685 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3686 if (NextMenuOption
->Row
== 0) {
3687 UpdateOptionSkipLines (NextMenuOption
);
3691 // Calculate new highlight menu end row.
3693 Temp
= (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
) + Difference
+ NextMenuOption
->Skip
- 1;
3694 if (Temp
> BottomRow
) {
3696 // Get the top screen menu info.
3698 AdjustDateAndTimePosition (FALSE
, &TopOfScreen
);
3699 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3702 // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
3703 // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
3705 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3707 // Skip the top op-code
3709 TopOfScreen
= TopOfScreen
->ForwardLink
;
3710 DistanceValue
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3712 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3715 // If we have a remainder, skip that many more op-codes until we drain the remainder
3716 // Special case is the selected highlight menu has more than one form of menus.
3718 while (DistanceValue
>= SavedMenuOption
->Skip
&& TopOfScreen
!= NewPos
) {
3720 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3722 DistanceValue
= DistanceValue
- (INTN
) SavedMenuOption
->Skip
;
3723 TopOfScreen
= TopOfScreen
->ForwardLink
;
3724 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3727 // Since we will act on this op-code in the next routine, and increment the
3728 // SkipValue, set the skips to one less than what is required.
3730 if (TopOfScreen
!= NewPos
) {
3731 SkipValue
= DistanceValue
;
3737 // Since we will act on this op-code in the next routine, and increment the
3738 // SkipValue, set the skips to one less than what is required.
3740 SkipValue
+= Temp
- BottomRow
;
3743 } else if (!IsSelectable (NextMenuOption
)) {
3745 // Continue to go down until scroll to next page or the selectable option is found.
3747 ScreenOperation
= UiDown
;
3748 ControlFlag
= CfScreenOperation
;
3752 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3755 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3757 // BottomRow - TopRow + 1 means the total rows current forms supported.
3758 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3759 // and new top menu. New top menu will all shows in next form, but last highlight menu
3760 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3761 // last highlight menu.
3763 if (!IsSelectable (NextMenuOption
) && IsSelectable (MenuOption
) &&
3764 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3765 NewPos
= SavedListEntry
;
3768 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3771 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3773 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3774 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3776 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3779 case CfUiNoOperation
:
3780 ControlFlag
= CfRepaint
;
3784 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3785 if (HelpString
!= NULL
) {
3786 FreePool (HelpString
);
3788 if (HelpHeaderString
!= NULL
) {
3789 FreePool (HelpHeaderString
);
3791 if (HelpBottomString
!= NULL
) {
3792 FreePool (HelpBottomString
);
3803 Free the UI Menu Option structure data.
3805 @param MenuOptionList Point to the menu option list which need to be free.
3810 LIST_ENTRY
*MenuOptionList
3814 UI_MENU_OPTION
*Option
;
3817 // Free menu option list
3819 while (!IsListEmpty (MenuOptionList
)) {
3820 Link
= GetFirstNode (MenuOptionList
);
3821 Option
= MENU_OPTION_FROM_LINK (Link
);
3822 if (Option
->Description
!= NULL
){
3823 FreePool(Option
->Description
);
3825 RemoveEntryList (&Option
->Link
);
3832 Base on the browser status info to show an pop up message.
3836 BrowserStatusProcess (
3842 EFI_EVENT WaitList
[2];
3843 EFI_EVENT RefreshIntervalEvent
;
3844 EFI_EVENT TimeOutEvent
;
3848 WARNING_IF_CONTEXT EventContext
;
3849 EFI_IFR_OP_HEADER
*OpCodeBuf
;
3850 EFI_STRING_ID StringToken
;
3851 CHAR16 DiscardChange
;
3852 CHAR16 JumpToFormSet
;
3853 CHAR16
*PrintString
;
3855 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3860 TimeOutEvent
= NULL
;
3861 RefreshIntervalEvent
= NULL
;
3863 if (gFormData
->HighLightedStatement
!= NULL
) {
3864 OpCodeBuf
= gFormData
->HighLightedStatement
->OpCode
;
3867 if (gFormData
->BrowserStatus
== (BROWSER_WARNING_IF
)) {
3868 ASSERT (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_WARNING_IF_OP
);
3870 TimeOut
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->TimeOut
;
3871 StringToken
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->Warning
;
3874 if ((gFormData
->BrowserStatus
== (BROWSER_NO_SUBMIT_IF
)) &&
3875 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_NO_SUBMIT_IF_OP
)) {
3876 StringToken
= ((EFI_IFR_NO_SUBMIT_IF
*) OpCodeBuf
)->Error
;
3877 } else if ((gFormData
->BrowserStatus
== (BROWSER_INCONSISTENT_IF
)) &&
3878 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_INCONSISTENT_IF_OP
)) {
3879 StringToken
= ((EFI_IFR_INCONSISTENT_IF
*) OpCodeBuf
)->Error
;
3883 if (StringToken
!= 0) {
3884 ErrorInfo
= GetToken (StringToken
, gFormData
->HiiHandle
);
3885 } else if (gFormData
->ErrorString
!= NULL
) {
3887 // Only used to compatible with old setup browser.
3888 // Not use this field in new browser core.
3890 ErrorInfo
= gFormData
->ErrorString
;
3892 switch (gFormData
->BrowserStatus
) {
3893 case BROWSER_SUBMIT_FAIL
:
3894 ErrorInfo
= gSaveFailed
;
3897 case BROWSER_FORM_NOT_FOUND
:
3898 ErrorInfo
= gFormNotFound
;
3901 case BROWSER_FORM_SUPPRESS
:
3902 ErrorInfo
= gFormSuppress
;
3905 case BROWSER_PROTOCOL_NOT_FOUND
:
3906 ErrorInfo
= gProtocolNotFound
;
3909 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3910 ErrorInfo
= gNoSubmitIfFailed
;
3913 case BROWSER_RECONNECT_FAIL
:
3914 ErrorInfo
= gReconnectFail
;
3917 case BROWSER_RECONNECT_SAVE_CHANGES
:
3918 ErrorInfo
= gReconnectConfirmChanges
;
3921 case BROWSER_RECONNECT_REQUIRED
:
3922 ErrorInfo
= gReconnectRequired
;
3926 ErrorInfo
= gBrowserError
;
3931 switch (gFormData
->BrowserStatus
) {
3932 case BROWSER_SUBMIT_FAIL
:
3933 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3934 case BROWSER_RECONNECT_SAVE_CHANGES
:
3935 ASSERT (gUserInput
!= NULL
);
3936 if (gFormData
->BrowserStatus
== (BROWSER_SUBMIT_FAIL
)) {
3937 PrintString
= gSaveProcess
;
3938 JumpToFormSet
= gJumpToFormSet
[0];
3939 DiscardChange
= gDiscardChange
[0];
3940 } else if (gFormData
->BrowserStatus
== (BROWSER_RECONNECT_SAVE_CHANGES
)){
3941 PrintString
= gChangesOpt
;
3942 JumpToFormSet
= gConfirmOptYes
[0];
3943 DiscardChange
= gConfirmOptNo
[0];
3945 PrintString
= gSaveNoSubmitProcess
;
3946 JumpToFormSet
= gCheckError
[0];
3947 DiscardChange
= gDiscardChange
[0];
3951 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, PrintString
, gEmptyString
, NULL
);
3952 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) &&
3953 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (JumpToFormSet
| UPPER_LOWER_CASE_OFFSET
)));
3955 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) {
3956 gUserInput
->Action
= BROWSER_ACTION_DISCARD
;
3958 gUserInput
->Action
= BROWSER_ACTION_GOTO
;
3965 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3966 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3968 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
3969 ASSERT_EFI_ERROR (Status
);
3971 EventContext
.SyncEvent
= TimeOutEvent
;
3972 EventContext
.TimeOut
= &TimeOut
;
3973 EventContext
.ErrorInfo
= ErrorInfo
;
3975 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
3976 ASSERT_EFI_ERROR (Status
);
3979 // Show the dialog first to avoid long time not reaction.
3981 gBS
->SignalEvent (RefreshIntervalEvent
);
3983 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
3984 ASSERT_EFI_ERROR (Status
);
3987 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3988 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3992 if (Status
!= EFI_NOT_READY
) {
3996 WaitList
[0] = TimeOutEvent
;
3997 WaitList
[1] = gST
->ConIn
->WaitForKey
;
3999 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
4000 ASSERT_EFI_ERROR (Status
);
4004 // Timeout occur, close the hoot time out event.
4010 gBS
->CloseEvent (TimeOutEvent
);
4011 gBS
->CloseEvent (RefreshIntervalEvent
);
4016 if (StringToken
!= 0) {
4017 FreePool (ErrorInfo
);
4022 Display one form, and return user input.
4024 @param FormData Form Data to be shown.
4025 @param UserInputData User input data.
4027 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
4028 2.Error info has show and return.
4029 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
4030 @retval EFI_NOT_FOUND New form data has some error.
4035 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
4036 OUT USER_INPUT
*UserInputData
4041 ASSERT (FormData
!= NULL
);
4042 if (FormData
== NULL
) {
4043 return EFI_INVALID_PARAMETER
;
4046 gUserInput
= UserInputData
;
4047 gFormData
= FormData
;
4050 // Process the status info first.
4052 BrowserStatusProcess();
4053 if (gFormData
->BrowserStatus
!= BROWSER_SUCCESS
) {
4055 // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
4060 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
4061 if (EFI_ERROR (Status
)) {
4066 // Global Widths should be initialized before any MenuOption creation
4067 // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
4071 // |<-.->|<-.........->|<- .........->|<-...........->|
4072 // Skip Prompt Option Help
4074 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3) + 1;
4075 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- 1 - LEFT_SKIPPED_COLUMNS
);
4076 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gOptionBlockWidth
- 1) - 1);
4078 ConvertStatementToMenu();
4081 // Check whether layout is changed.
4084 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
4085 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
4086 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
4087 mStatementLayoutIsChanged
= TRUE
;
4089 mStatementLayoutIsChanged
= FALSE
;
4092 Status
= UiDisplayMenu(FormData
);
4095 // Backup last form info.
4097 mIsFirstForm
= FALSE
;
4098 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
4099 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
4100 gOldFormEntry
.FormId
= FormData
->FormId
;
4103 //Free the Ui menu option list.
4105 FreeMenuOptionData(&gMenuOption
);
4111 Clear Screen to the initial state.
4115 DriverClearDisplayPage (
4119 ClearDisplayPage ();
4120 mIsFirstForm
= TRUE
;
4124 Set Buffer to Value for Size bytes.
4126 @param Buffer Memory to set.
4127 @param Size Number of bytes to set
4128 @param Value Value of the set operation.
4141 while ((Size
--) != 0) {
4147 Initialize Setup Browser driver.
4149 @param ImageHandle The image handle.
4150 @param SystemTable The system table.
4152 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
4153 @return Other value if failed to initialize the Setup Browser module.
4158 InitializeDisplayEngine (
4159 IN EFI_HANDLE ImageHandle
,
4160 IN EFI_SYSTEM_TABLE
*SystemTable
4164 EFI_INPUT_KEY HotKey
;
4165 EFI_STRING NewString
;
4166 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
4169 // Publish our HII data
4171 gHiiHandle
= HiiAddPackages (
4172 &gDisplayEngineGuid
,
4174 DisplayEngineStrings
,
4177 ASSERT (gHiiHandle
!= NULL
);
4180 // Install Form Display protocol
4182 Status
= gBS
->InstallProtocolInterface (
4183 &mPrivateData
.Handle
,
4184 &gEdkiiFormDisplayEngineProtocolGuid
,
4185 EFI_NATIVE_INTERFACE
,
4186 &mPrivateData
.FromDisplayProt
4188 ASSERT_EFI_ERROR (Status
);
4191 // Install HII Popup Protocol.
4193 Status
= gBS
->InstallProtocolInterface (
4194 &mPrivateData
.Handle
,
4195 &gEfiHiiPopupProtocolGuid
,
4196 EFI_NATIVE_INTERFACE
,
4197 &mPrivateData
.HiiPopup
4199 ASSERT_EFI_ERROR (Status
);
4201 InitializeDisplayStrings();
4203 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
4204 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
4207 // Use BrowserEx2 protocol to register HotKey.
4209 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
4210 if (!EFI_ERROR (Status
)) {
4212 // Register the default HotKey F9 and F10 again.
4214 HotKey
.UnicodeChar
= CHAR_NULL
;
4215 HotKey
.ScanCode
= SCAN_F10
;
4216 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
4217 ASSERT (NewString
!= NULL
);
4218 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
4219 FreePool (NewString
);
4221 HotKey
.ScanCode
= SCAN_F9
;
4222 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
4223 ASSERT (NewString
!= NULL
);
4224 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
4225 FreePool (NewString
);
4232 This is the default unload handle for display core drivers.
4234 @param[in] ImageHandle The drivers' driver image.
4236 @retval EFI_SUCCESS The image is unloaded.
4237 @retval Others Failed to unload the image.
4242 UnloadDisplayEngine (
4243 IN EFI_HANDLE ImageHandle
4246 HiiRemovePackages(gHiiHandle
);
4248 FreeDisplayStrings ();
4250 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
4251 FreePool (gHighligthMenuInfo
.HLTOpCode
);
4254 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
4255 FreePool (gHighligthMenuInfo
.TOSOpCode
);