2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FormDisplay.h"
19 // Search table for UiDisplayMenu()
21 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
52 UINTN mScanCodeNumber
= ARRAY_SIZE (gScanCodeToOperation
);
54 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
97 EFI_GUID gDisplayEngineGuid
= {
98 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
102 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
103 BOOLEAN mStatementLayoutIsChanged
= TRUE
;
104 USER_INPUT
*gUserInput
;
105 FORM_DISPLAY_ENGINE_FORM
*gFormData
;
106 EFI_HII_HANDLE gHiiHandle
;
108 LIST_ENTRY gMenuOption
;
109 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo
= {0};
110 BOOLEAN mIsFirstForm
= TRUE
;
111 FORM_ENTRY_INFO gOldFormEntry
= {0};
114 // Browser Global Strings
116 CHAR16
*gReconnectConfirmChanges
;
117 CHAR16
*gReconnectFail
;
118 CHAR16
*gReconnectRequired
;
120 CHAR16
*gFormNotFound
;
122 CHAR16
*gBrowserError
;
124 CHAR16
*gNoSubmitIfFailed
;
125 CHAR16
*gSaveProcess
;
126 CHAR16
*gSaveNoSubmitProcess
;
127 CHAR16
*gDiscardChange
;
128 CHAR16
*gJumpToFormSet
;
130 CHAR16
*gPromptForData
;
131 CHAR16
*gPromptForPassword
;
132 CHAR16
*gPromptForNewPassword
;
133 CHAR16
*gConfirmPassword
;
134 CHAR16
*gConfirmError
;
135 CHAR16
*gPassowordInvalid
;
137 CHAR16
*gEmptyString
;
139 CHAR16
*gOptionMismatch
;
140 CHAR16
*gFormSuppress
;
141 CHAR16
*gProtocolNotFound
;
142 CHAR16
*gConfirmDefaultMsg
;
143 CHAR16
*gConfirmSubmitMsg
;
144 CHAR16
*gConfirmDiscardMsg
;
145 CHAR16
*gConfirmResetMsg
;
146 CHAR16
*gConfirmExitMsg
;
147 CHAR16
*gConfirmSubmitMsg2nd
;
148 CHAR16
*gConfirmDefaultMsg2nd
;
149 CHAR16
*gConfirmResetMsg2nd
;
150 CHAR16
*gConfirmExitMsg2nd
;
152 CHAR16
*gConfirmOptYes
;
153 CHAR16
*gConfirmOptNo
;
154 CHAR16
*gConfirmOptOk
;
155 CHAR16
*gConfirmOptCancel
;
159 CHAR16
*gCancelOption
;
161 CHAR16
*gWarningPopup
;
163 CHAR16
*gConfirmMsgConnect
;
164 CHAR16
*gConfirmMsgEnd
;
165 CHAR16
*gPasswordUnsupported
;
166 CHAR16 gModalSkipColumn
;
167 CHAR16 gPromptBlockWidth
;
168 CHAR16 gOptionBlockWidth
;
169 CHAR16 gHelpBlockWidth
;
170 CHAR16
*mUnknownString
;
172 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
173 FORM_DISPLAY_DRIVER_SIGNATURE
,
177 DriverClearDisplayPage
,
181 EFI_HII_POPUP_PROTOCOL_REVISION
,
188 Get the string based on the StringId and HII Package List Handle.
190 @param Token The String's ID.
191 @param HiiHandle The package list in the HII database to search for
192 the specified string.
194 @return The output string.
199 IN EFI_STRING_ID Token
,
200 IN EFI_HII_HANDLE HiiHandle
205 String
= HiiGetString (HiiHandle
, Token
, NULL
);
206 if (String
== NULL
) {
207 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
208 ASSERT (String
!= NULL
);
211 return (CHAR16
*) String
;
216 Initialize the HII String Token to the correct values.
220 InitializeDisplayStrings (
224 gReconnectConfirmChanges
= GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES
), gHiiHandle
);
225 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
226 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
227 gNoSubmitIfFailed
= GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED
), gHiiHandle
);
228 gReconnectFail
= GetToken (STRING_TOKEN (RECONNECT_FAILED
), gHiiHandle
);
229 gReconnectRequired
= GetToken (STRING_TOKEN (RECONNECT_REQUIRED
), gHiiHandle
);
230 gChangesOpt
= GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS
), gHiiHandle
);
231 gSaveProcess
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP
), gHiiHandle
);
232 gSaveNoSubmitProcess
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK
), gHiiHandle
);
233 gDiscardChange
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD
), gHiiHandle
);
234 gJumpToFormSet
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP
), gHiiHandle
);
235 gCheckError
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK
), gHiiHandle
);
236 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
237 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
238 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
239 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
240 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
241 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
242 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
243 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
244 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
245 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
246 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
247 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
248 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
249 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
250 gBrowserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
251 gConfirmDefaultMsg
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE
), gHiiHandle
);
252 gConfirmDiscardMsg
= GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE
), gHiiHandle
);
253 gConfirmSubmitMsg
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE
), gHiiHandle
);
254 gConfirmResetMsg
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE
), gHiiHandle
);
255 gConfirmExitMsg
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE
), gHiiHandle
);
256 gConfirmDefaultMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND
), gHiiHandle
);
257 gConfirmSubmitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND
), gHiiHandle
);
258 gConfirmResetMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND
), gHiiHandle
);
259 gConfirmExitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND
), gHiiHandle
);
260 gConfirmOpt
= GetToken (STRING_TOKEN (CONFIRM_OPTION
), gHiiHandle
);
261 gConfirmOptYes
= GetToken (STRING_TOKEN (CONFIRM_OPTION_YES
), gHiiHandle
);
262 gConfirmOptNo
= GetToken (STRING_TOKEN (CONFIRM_OPTION_NO
), gHiiHandle
);
263 gConfirmOptOk
= GetToken (STRING_TOKEN (CONFIRM_OPTION_OK
), gHiiHandle
);
264 gConfirmOptCancel
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CANCEL
), gHiiHandle
);
265 gYesOption
= GetToken (STRING_TOKEN (YES_SELECTABLE_OPTION
), gHiiHandle
);
266 gNoOption
= GetToken (STRING_TOKEN (NO_SELECTABLE_OPTION
), gHiiHandle
);
267 gOkOption
= GetToken (STRING_TOKEN (OK_SELECTABLE_OPTION
), gHiiHandle
);
268 gCancelOption
= GetToken (STRING_TOKEN (CANCEL_SELECTABLE_OPTION
), gHiiHandle
);
269 gErrorPopup
= GetToken (STRING_TOKEN (ERROR_POPUP_STRING
), gHiiHandle
);
270 gWarningPopup
= GetToken (STRING_TOKEN (WARNING_POPUP_STRING
), gHiiHandle
);
271 gInfoPopup
= GetToken (STRING_TOKEN (INFO_POPUP_STRING
), gHiiHandle
);
272 gConfirmMsgConnect
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT
), gHiiHandle
);
273 gConfirmMsgEnd
= GetToken (STRING_TOKEN (CONFIRM_OPTION_END
), gHiiHandle
);
274 gPasswordUnsupported
= GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED
), gHiiHandle
);
278 Free up the resource allocated for all strings required
287 FreePool (mUnknownString
);
288 FreePool (gEmptyString
);
289 FreePool (gSaveFailed
);
290 FreePool (gNoSubmitIfFailed
);
291 FreePool (gReconnectFail
);
292 FreePool (gReconnectRequired
);
293 FreePool (gChangesOpt
);
294 FreePool (gReconnectConfirmChanges
);
295 FreePool (gSaveProcess
);
296 FreePool (gSaveNoSubmitProcess
);
297 FreePool (gDiscardChange
);
298 FreePool (gJumpToFormSet
);
299 FreePool (gCheckError
);
300 FreePool (gPromptForData
);
301 FreePool (gPromptForPassword
);
302 FreePool (gPromptForNewPassword
);
303 FreePool (gConfirmPassword
);
304 FreePool (gConfirmError
);
305 FreePool (gPassowordInvalid
);
306 FreePool (gPressEnter
);
307 FreePool (gMiniString
);
308 FreePool (gOptionMismatch
);
309 FreePool (gFormSuppress
);
310 FreePool (gProtocolNotFound
);
311 FreePool (gBrowserError
);
312 FreePool (gNoSubmitIf
);
313 FreePool (gFormNotFound
);
314 FreePool (gConfirmDefaultMsg
);
315 FreePool (gConfirmSubmitMsg
);
316 FreePool (gConfirmDiscardMsg
);
317 FreePool (gConfirmResetMsg
);
318 FreePool (gConfirmExitMsg
);
319 FreePool (gConfirmDefaultMsg2nd
);
320 FreePool (gConfirmSubmitMsg2nd
);
321 FreePool (gConfirmResetMsg2nd
);
322 FreePool (gConfirmExitMsg2nd
);
323 FreePool (gConfirmOpt
);
324 FreePool (gConfirmOptYes
);
325 FreePool (gConfirmOptNo
);
326 FreePool (gConfirmOptOk
);
327 FreePool (gConfirmOptCancel
);
328 FreePool (gYesOption
);
329 FreePool (gNoOption
);
330 FreePool (gOkOption
);
331 FreePool (gCancelOption
);
332 FreePool (gErrorPopup
);
333 FreePool (gWarningPopup
);
334 FreePool (gInfoPopup
);
335 FreePool (gConfirmMsgConnect
);
336 FreePool (gConfirmMsgEnd
);
337 FreePool (gPasswordUnsupported
);
341 Get prompt string id from the opcode data buffer.
343 @param OpCode The input opcode buffer.
345 @return The prompt string id.
350 IN EFI_IFR_OP_HEADER
*OpCode
353 EFI_IFR_STATEMENT_HEADER
*Header
;
355 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
359 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
361 return Header
->Prompt
;
365 Get the supported width for a particular op-code
367 @param MenuOption The menu option.
368 @param AdjustWidth The width which is saved for the space.
370 @return Returns the number of CHAR16 characters that is support.
375 IN UI_MENU_OPTION
*MenuOption
,
376 OUT UINT16
*AdjustWidth
381 EFI_IFR_TEXT
*TestOp
;
383 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
385 Statement
= MenuOption
->ThisTag
;
388 // For modal form, clean the entire row.
390 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
391 if (AdjustWidth
!= NULL
) {
392 *AdjustWidth
= LEFT_SKIPPED_COLUMNS
;
394 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gModalSkipColumn
+ LEFT_SKIPPED_COLUMNS
));
400 // See if the second text parameter is really NULL
402 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
403 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
404 if (TestOp
->TextTwo
!= 0) {
405 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
406 Size
= StrLen (String
);
411 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
412 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
413 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
414 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
415 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
417 // Allow a wide display if text op-code and no secondary text op-code
419 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
423 // Return the space width.
425 if (AdjustWidth
!= NULL
) {
429 // Keep consistent with current behavior.
431 ReturnWidth
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
433 if (AdjustWidth
!= NULL
) {
437 ReturnWidth
= (UINT16
) (gPromptBlockWidth
- 1);
441 // For nest in statement, should the subtitle indent.
443 if (MenuOption
->NestInStatement
) {
444 ReturnWidth
-= SUBTITLE_INDENT
;
451 Will copy LineWidth amount of a string in the OutputString buffer and return the
452 number of CHAR16 characters that were copied into the OutputString buffer.
453 The output string format is:
454 Glyph Info + String info + '\0'.
456 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
458 @param InputString String description for this option.
459 @param LineWidth Width of the desired string to extract in CHAR16
461 @param GlyphWidth The glyph width of the begin of the char in the string.
462 @param Index Where in InputString to start the copy process
463 @param OutputString Buffer to copy the string into
465 @return Returns the number of CHAR16 characters that were copied into the OutputString
466 buffer, include extra glyph info and '\0' info.
471 IN CHAR16
*InputString
,
473 IN OUT UINT16
*GlyphWidth
,
475 OUT CHAR16
**OutputString
480 UINT16 OriginalGlyphWidth
;
482 UINT16 LastSpaceOffset
;
483 UINT16 LastGlyphWidth
;
485 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
489 if (LineWidth
== 0 || *GlyphWidth
== 0) {
494 // Save original glyph width.
496 OriginalGlyphWidth
= *GlyphWidth
;
497 LastGlyphWidth
= OriginalGlyphWidth
;
502 // 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.
503 // To avoid displaying this empty line in screen, just skip the two CHARs here.
505 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
510 // Fast-forward the string and see if there is a carriage-return in the string
512 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
513 switch (InputString
[*Index
+ StrOffset
]) {
522 case CHAR_CARRIAGE_RETURN
:
529 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
532 // Record the last space info in this line. Will be used in rewind.
534 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
535 LastSpaceOffset
= StrOffset
;
536 LastGlyphWidth
= *GlyphWidth
;
547 // Rewind the string from the maximum size until we see a space to break the line
549 if (GlyphOffset
> LineWidth
) {
551 // Rewind the string to last space char in this line.
553 if (LastSpaceOffset
!= 0) {
554 StrOffset
= LastSpaceOffset
;
555 *GlyphWidth
= LastGlyphWidth
;
558 // Roll back to last char in the line width.
565 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
567 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
572 // Need extra glyph info and '\0' info, so +2.
574 *OutputString
= AllocateZeroPool ((StrOffset
+ 2) * sizeof(CHAR16
));
575 if (*OutputString
== NULL
) {
580 // Save the glyph info at the begin of the string, will used by Print function.
582 if (OriginalGlyphWidth
== 1) {
583 *(*OutputString
) = NARROW_CHAR
;
585 *(*OutputString
) = WIDE_CHAR
;
588 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
590 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
592 // Skip the space info at the begin of next line.
594 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
595 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
597 // Skip the /n or /n/r info.
599 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
600 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
602 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
604 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
606 // Skip the /r or /r/n info.
608 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
609 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
611 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
614 *Index
= (UINT16
) (*Index
+ StrOffset
);
618 // Include extra glyph info and '\0' info, so +2.
620 return StrOffset
+ 2;
624 Add one menu option by specified description and context.
626 @param Statement Statement of this Menu Option.
627 @param MenuItemCount The index for this Option in the Menu.
628 @param NestIn Whether this statement is nest in another statement.
633 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
634 IN UINT16
*MenuItemCount
,
638 UI_MENU_OPTION
*MenuOption
;
641 UINT16 NumberOfLines
;
645 CHAR16
*OutputString
;
646 EFI_STRING_ID PromptId
;
654 PromptId
= GetPrompt (Statement
->OpCode
);
655 ASSERT (PromptId
!= 0);
657 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
661 for (Index
= 0; Index
< Count
; Index
++) {
662 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
665 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
666 MenuOption
->Description
= GetToken (PromptId
, gFormData
->HiiHandle
);
667 MenuOption
->Handle
= gFormData
->HiiHandle
;
668 MenuOption
->ThisTag
= Statement
;
669 MenuOption
->NestInStatement
= NestIn
;
670 MenuOption
->EntryNumber
= *MenuItemCount
;
672 MenuOption
->Sequence
= Index
;
674 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
675 MenuOption
->GrayOut
= TRUE
;
677 MenuOption
->GrayOut
= FALSE
;
680 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
681 MenuOption
->GrayOut
= TRUE
;
685 // If the form or the question has the lock attribute, deal same as grayout.
687 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
688 MenuOption
->GrayOut
= TRUE
;
691 switch (Statement
->OpCode
->OpCode
) {
692 case EFI_IFR_ORDERED_LIST_OP
:
693 case EFI_IFR_ONE_OF_OP
:
694 case EFI_IFR_NUMERIC_OP
:
695 case EFI_IFR_TIME_OP
:
696 case EFI_IFR_DATE_OP
:
697 case EFI_IFR_CHECKBOX_OP
:
698 case EFI_IFR_PASSWORD_OP
:
699 case EFI_IFR_STRING_OP
:
701 // User could change the value of these items
703 MenuOption
->IsQuestion
= TRUE
;
705 case EFI_IFR_TEXT_OP
:
706 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
708 // Initializing GrayOut option as TRUE for Text setup options
709 // so that those options will be Gray in colour and un selectable.
711 MenuOption
->GrayOut
= TRUE
;
715 MenuOption
->IsQuestion
= FALSE
;
719 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
720 MenuOption
->ReadOnly
= TRUE
;
721 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
722 MenuOption
->GrayOut
= TRUE
;
727 (Statement
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
728 (Statement
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
729 Width
= GetWidth (MenuOption
, NULL
);
730 for (; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
732 // If there is more string to process print on the next row and increment the Skip value
734 if (StrLen (&MenuOption
->Description
[ArrayEntry
]) != 0) {
737 FreePool (OutputString
);
741 // Add three MenuOptions for Date/Time
742 // Data format : [01/02/2004] [11:22:33]
743 // Line number : 0 0 1 0 0 1
750 // Override LineNumber for the MenuOption in Date/Time sequence
752 MenuOption
->Skip
= 1;
754 MenuOption
->Skip
= NumberOfLines
;
757 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
764 Create the menu list base on the form data info.
768 ConvertStatementToMenu (
772 UINT16 MenuItemCount
;
774 LIST_ENTRY
*NestLink
;
775 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
776 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
779 InitializeListHead (&gMenuOption
);
781 Link
= GetFirstNode (&gFormData
->StatementListHead
);
782 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
783 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
784 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
787 // Skip the opcode not recognized by Display core.
789 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
793 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
796 // Check the statement nest in this host statement.
798 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
799 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
800 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
801 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
804 // Skip the opcode not recognized by Display core.
806 if (NestStatement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
810 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
816 Count the storage space of a Unicode string.
818 This function handles the Unicode string with NARROW_CHAR
819 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
820 does not count in the resultant output. If a WIDE_CHAR is
821 hit, then 2 Unicode character will consume an output storage
822 space with size of CHAR16 till a NARROW_CHAR is hit.
824 If String is NULL, then ASSERT ().
826 @param String The input string to be counted.
828 @return Storage space for the input string.
838 UINTN IncrementValue
;
840 ASSERT (String
!= NULL
);
841 if (String
== NULL
) {
851 // Advance to the null-terminator or to the first width directive
854 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
855 Index
++, Count
= Count
+ IncrementValue
860 // We hit the null-terminator, we now have a count
862 if (String
[Index
] == 0) {
866 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
867 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
869 if (String
[Index
] == NARROW_CHAR
) {
871 // Skip to the next character
877 // Skip to the next character
882 } while (String
[Index
] != 0);
885 // Increment by one to include the null-terminator in the size
889 return Count
* sizeof (CHAR16
);
893 Base on the input option string to update the skip value for a menu option.
895 @param MenuOption The MenuOption to be checked.
896 @param OptionString The input option string.
900 UpdateSkipInfoForMenu (
901 IN UI_MENU_OPTION
*MenuOption
,
902 IN CHAR16
*OptionString
908 CHAR16
*OutputString
;
911 Width
= (UINT16
) gOptionBlockWidth
- 1;
915 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
916 if (StrLen (&OptionString
[Index
]) != 0) {
920 FreePool (OutputString
);
923 if ((Row
> MenuOption
->Skip
) &&
924 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
925 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
926 MenuOption
->Skip
= Row
;
931 Update display lines for a Menu Option.
933 @param MenuOption The MenuOption to be checked.
937 UpdateOptionSkipLines (
938 IN UI_MENU_OPTION
*MenuOption
941 CHAR16
*OptionString
;
945 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
946 if (OptionString
!= NULL
) {
947 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
949 FreePool (OptionString
);
952 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
953 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
955 if (OptionString
!= NULL
) {
956 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
958 FreePool (OptionString
);
964 Check whether this Menu Option could be print.
966 Check Prompt string, option string or text two string not NULL.
968 This is an internal function.
970 @param MenuOption The MenuOption to be checked.
972 @retval TRUE This Menu Option is printable.
973 @retval FALSE This Menu Option could not be printable.
978 UI_MENU_OPTION
*MenuOption
982 EFI_STRING OptionString
;
986 if (MenuOption
->Description
[0] != '\0') {
990 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
991 if (EFI_ERROR (Status
)) {
994 if (OptionString
!= NULL
&& OptionString
[0] != '\0') {
995 FreePool (OptionString
);
999 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
1000 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1001 ASSERT (OptionString
!= NULL
);
1002 if (OptionString
[0] != '\0'){
1003 FreePool (OptionString
);
1012 Check whether this Menu Option could be highlighted.
1014 This is an internal function.
1016 @param MenuOption The MenuOption to be checked.
1018 @retval TRUE This Menu Option is selectable.
1019 @retval FALSE This Menu Option could not be selected.
1024 UI_MENU_OPTION
*MenuOption
1027 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
1028 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
|| !PrintableMenu (MenuOption
)) {
1036 Move to next selectable statement.
1038 This is an internal function.
1040 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1041 @param CurrentPosition Current position.
1042 @param GapToTop Gap position to top or bottom.
1043 @param FindInForm Whether find menu in current form or beyond.
1045 @return The row distance from current MenuOption to next selectable MenuOption.
1047 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
1048 @retval Value Find the selectable menu, maybe the truly selectable, maybe the
1049 first menu showing beyond current form or last menu showing in
1051 The value is the line number between the new selected menu and the
1052 current select menu, not include the new selected menu.
1056 MoveToNextStatement (
1058 IN OUT LIST_ENTRY
**CurrentPosition
,
1060 IN BOOLEAN FindInForm
1065 UI_MENU_OPTION
*NextMenuOption
;
1066 UI_MENU_OPTION
*PreMenuOption
;
1069 Pos
= *CurrentPosition
;
1071 if (Pos
== &gMenuOption
) {
1075 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1078 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1080 // NextMenuOption->Row == 0 means this menu has not calculate
1081 // the NextMenuOption->Skip value yet, just calculate here.
1083 if (NextMenuOption
->Row
== 0) {
1084 UpdateOptionSkipLines (NextMenuOption
);
1088 // Check whether the menu is beyond current showing form,
1089 // return the first one beyond the showing form.
1091 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1093 NextMenuOption
= PreMenuOption
;
1099 // return the selectable menu in the showing form.
1101 if (IsSelectable (NextMenuOption
)) {
1105 Distance
+= NextMenuOption
->Skip
;
1108 // Arrive at begin of the menu list.
1110 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1115 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1116 PreMenuOption
= NextMenuOption
;
1119 *CurrentPosition
= &NextMenuOption
->Link
;
1125 Process option string for date/time opcode.
1127 @param MenuOption Menu option point to date/time.
1128 @param OptionString Option string input for process.
1129 @param AddOptCol Whether need to update MenuOption->OptCol.
1133 ProcessStringForDateTime (
1134 UI_MENU_OPTION
*MenuOption
,
1135 CHAR16
*OptionString
,
1141 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1145 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
1147 Statement
= MenuOption
->ThisTag
;
1150 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1151 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
1152 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1153 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
1157 // If leading spaces on OptionString - remove the spaces
1159 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1161 // Base on the blockspace to get the option column info.
1164 MenuOption
->OptCol
++;
1168 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1169 OptionString
[Count
] = OptionString
[Index
];
1172 OptionString
[Count
] = CHAR_NULL
;
1175 // Enable to suppress field in the opcode base on the flag.
1177 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1179 // OptionString format is: <**: **: ****>
1183 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1185 // At this point, only "<**:" in the optionstring.
1186 // Clean the day's ** field, after clean, the format is "< :"
1188 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1189 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1191 // At this point, only "**:" in the optionstring.
1192 // Clean the month's "**" field, after clean, the format is " :"
1194 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1195 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1197 // At this point, only "****>" in the optionstring.
1198 // Clean the year's "****" field, after clean, the format is " >"
1200 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1202 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1204 // OptionString format is: <**: **: **>
1205 // |hour|minute|second|
1208 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1210 // At this point, only "<**:" in the optionstring.
1211 // Clean the hour's ** field, after clean, the format is "< :"
1213 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1214 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1216 // At this point, only "**:" in the optionstring.
1217 // Clean the minute's "**" field, after clean, the format is " :"
1219 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1220 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1222 // At this point, only "**>" in the optionstring.
1223 // Clean the second's "**" field, after clean, the format is " >"
1225 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1232 Adjust Data and Time position accordingly.
1233 Data format : [01/02/2004] [11:22:33]
1234 Line number : 0 0 1 0 0 1
1236 This is an internal function.
1238 @param DirectionUp the up or down direction. False is down. True is
1240 @param CurrentPosition Current position. On return: Point to the last
1241 Option (Year or Second) if up; Point to the first
1242 Option (Month or Hour) if down.
1244 @return Return line number to pad. It is possible that we stand on a zero-advance
1245 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1249 AdjustDateAndTimePosition (
1250 IN BOOLEAN DirectionUp
,
1251 IN OUT LIST_ENTRY
**CurrentPosition
1255 LIST_ENTRY
*NewPosition
;
1256 UI_MENU_OPTION
*MenuOption
;
1257 UINTN PadLineNumber
;
1260 NewPosition
= *CurrentPosition
;
1261 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1263 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1264 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1266 // Calculate the distance from current position to the last Date/Time MenuOption
1269 while (MenuOption
->Skip
== 0) {
1271 NewPosition
= NewPosition
->ForwardLink
;
1272 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1276 NewPosition
= *CurrentPosition
;
1279 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1280 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1281 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1282 // checking can be done.
1284 while (Count
++ < 2) {
1285 NewPosition
= NewPosition
->BackLink
;
1289 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1290 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1291 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1292 // checking can be done.
1294 while (Count
-- > 0) {
1295 NewPosition
= NewPosition
->ForwardLink
;
1299 *CurrentPosition
= NewPosition
;
1302 return PadLineNumber
;
1306 Get step info from numeric opcode.
1308 @param[in] OpCode The input numeric op code.
1310 @return step info for this opcode.
1314 IN EFI_IFR_OP_HEADER
*OpCode
1317 EFI_IFR_NUMERIC
*NumericOp
;
1320 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1322 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1323 case EFI_IFR_NUMERIC_SIZE_1
:
1324 Step
= NumericOp
->data
.u8
.Step
;
1327 case EFI_IFR_NUMERIC_SIZE_2
:
1328 Step
= NumericOp
->data
.u16
.Step
;
1331 case EFI_IFR_NUMERIC_SIZE_4
:
1332 Step
= NumericOp
->data
.u32
.Step
;
1335 case EFI_IFR_NUMERIC_SIZE_8
:
1336 Step
= NumericOp
->data
.u64
.Step
;
1348 Find the registered HotKey based on KeyData.
1350 @param[in] KeyData A pointer to a buffer that describes the keystroke
1351 information for the hot key.
1353 @return The registered HotKey context. If no found, NULL will return.
1356 GetHotKeyFromRegisterList (
1357 IN EFI_INPUT_KEY
*KeyData
1361 BROWSER_HOT_KEY
*HotKey
;
1363 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1364 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1365 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1367 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1371 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1379 Determine if the menu is the last menu that can be selected.
1381 This is an internal function.
1383 @param Direction The scroll direction. False is down. True is up.
1384 @param CurrentPos The current focus.
1386 @return FALSE -- the menu isn't the last menu that can be selected.
1387 @return TRUE -- the menu is the last menu that can be selected.
1392 IN BOOLEAN Direction
,
1393 IN LIST_ENTRY
*CurrentPos
1398 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1400 if (Temp
== &gMenuOption
) {
1408 Wait for a given event to fire, or for an optional timeout to expire.
1410 @param Event The event to wait for
1412 @retval UI_EVENT_TYPE The type of the event which is trigged.
1424 EFI_EVENT TimerEvent
;
1425 EFI_EVENT WaitList
[3];
1426 UI_EVENT_TYPE EventType
;
1429 Timeout
= FormExitTimeout(gFormData
);
1432 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1435 // Set the timer event
1444 WaitList
[0] = Event
;
1446 if (gFormData
->FormRefreshEvent
!= NULL
) {
1447 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1452 WaitList
[EventNum
] = TimerEvent
;
1456 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1457 ASSERT_EFI_ERROR (Status
);
1461 EventType
= UIEventKey
;
1465 if (gFormData
->FormRefreshEvent
!= NULL
) {
1466 EventType
= UIEventDriver
;
1468 ASSERT (Timeout
!= 0 && EventNum
== 2);
1469 EventType
= UIEventTimeOut
;
1474 ASSERT (Index
== 2 && EventNum
== 3);
1475 EventType
= UIEventTimeOut
;
1480 gBS
->CloseEvent (TimerEvent
);
1487 Get question id info from the input opcode header.
1489 @param OpCode The input opcode header pointer.
1491 @retval The question id for this opcode.
1496 IN EFI_IFR_OP_HEADER
*OpCode
1499 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1501 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1505 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1507 return QuestionHeader
->QuestionId
;
1512 Find the top of screen menu base on the current menu.
1514 @param CurPos Current input menu.
1515 @param Rows Totol screen rows.
1516 @param SkipValue SkipValue for this new form.
1518 @retval TopOfScreen Top of screen menu for the new form.
1522 FindTopOfScreenMenu (
1523 IN LIST_ENTRY
*CurPos
,
1525 OUT UINTN
*SkipValue
1529 LIST_ENTRY
*TopOfScreen
;
1530 UI_MENU_OPTION
*PreviousMenuOption
;
1533 PreviousMenuOption
= NULL
;
1535 while (Link
->BackLink
!= &gMenuOption
) {
1536 Link
= Link
->BackLink
;
1537 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1538 if (PreviousMenuOption
->Row
== 0) {
1539 UpdateOptionSkipLines (PreviousMenuOption
);
1541 if (Rows
<= PreviousMenuOption
->Skip
) {
1544 Rows
= Rows
- PreviousMenuOption
->Skip
;
1547 if (Link
->BackLink
== &gMenuOption
) {
1548 TopOfScreen
= gMenuOption
.ForwardLink
;
1549 if (PreviousMenuOption
!= NULL
&& Rows
< PreviousMenuOption
->Skip
) {
1550 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1556 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1563 Get the index info for this opcode.
1565 @param OpCode The input opcode for the statement.
1567 @retval The index of this statement.
1571 GetIndexInfoForOpcode (
1572 IN EFI_IFR_OP_HEADER
*OpCode
1576 UI_MENU_OPTION
*MenuOption
;
1579 NewPos
= gMenuOption
.ForwardLink
;
1582 for (NewPos
= gMenuOption
.ForwardLink
; NewPos
!= &gMenuOption
; NewPos
= NewPos
->ForwardLink
){
1583 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1585 if (CompareMem (MenuOption
->ThisTag
->OpCode
, OpCode
, OpCode
->Length
) == 0) {
1586 if (MenuOption
->ThisTag
->OpCode
== OpCode
) {
1598 Is this the saved highlight statement.
1600 @param HighLightedStatement The input highlight statement.
1602 @retval TRUE This is the highlight statement.
1603 @retval FALSE This is not the highlight statement.
1607 IsSavedHighlightStatement (
1608 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1611 if ((gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
) &&
1612 (gFormData
->FormId
== gHighligthMenuInfo
.FormId
)) {
1613 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1614 return (BOOLEAN
) (gHighligthMenuInfo
.HLTQuestionId
== GetQuestionIdInfo (HighLightedStatement
->OpCode
));
1616 if (CompareMem (gHighligthMenuInfo
.HLTOpCode
, HighLightedStatement
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1617 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(HighLightedStatement
->OpCode
)) {
1630 Is this the highlight menu.
1632 @param MenuOption The input Menu option.
1634 @retval TRUE This is the highlight menu option.
1635 @retval FALSE This is not the highlight menu option.
1639 IsHighLightMenuOption (
1640 IN UI_MENU_OPTION
*MenuOption
1643 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1644 if (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.HLTQuestionId
) {
1645 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1648 if(CompareMem (gHighligthMenuInfo
.HLTOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1649 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1650 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1661 Find the highlight menu.
1663 If the input is NULL, base on the record highlight info in
1664 gHighligthMenuInfo to find the last highlight menu.
1666 @param HighLightedStatement The input highlight statement.
1668 @retval The highlight menu index.
1672 FindHighLightMenuOption (
1673 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1677 UI_MENU_OPTION
*MenuOption
;
1679 NewPos
= gMenuOption
.ForwardLink
;
1680 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1682 if (HighLightedStatement
!= NULL
) {
1683 while (MenuOption
->ThisTag
!= HighLightedStatement
) {
1684 NewPos
= NewPos
->ForwardLink
;
1685 if (NewPos
== &gMenuOption
) {
1687 // Not Found it, break
1691 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1695 // Must find the highlight statement.
1697 ASSERT (NewPos
!= &gMenuOption
);
1700 while (!IsHighLightMenuOption (MenuOption
)) {
1701 NewPos
= NewPos
->ForwardLink
;
1702 if (NewPos
== &gMenuOption
) {
1704 // Not Found it, break
1708 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1712 // Highlight statement has disappear (suppressed/disableed)
1714 if (NewPos
== &gMenuOption
) {
1723 Is this the Top of screen menu.
1725 @param MenuOption The input Menu option.
1727 @retval TRUE This is the Top of screen menu option.
1728 @retval FALSE This is not the Top of screen menu option.
1732 IsTopOfScreeMenuOption (
1733 IN UI_MENU_OPTION
*MenuOption
1736 if (gHighligthMenuInfo
.TOSQuestionId
!= 0) {
1737 return (BOOLEAN
) (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.TOSQuestionId
);
1740 if(CompareMem (gHighligthMenuInfo
.TOSOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.TOSOpCode
->Length
) == 0) {
1741 if (gHighligthMenuInfo
.TOSIndex
== 0 || gHighligthMenuInfo
.TOSIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1752 Calculate the distance between two menus and include the skip value of StartMenu.
1754 @param StartMenu The link_entry pointer to start menu.
1755 @param EndMenu The link_entry pointer to end menu.
1759 GetDistanceBetweenMenus(
1760 IN LIST_ENTRY
*StartMenu
,
1761 IN LIST_ENTRY
*EndMenu
1765 UI_MENU_OPTION
*MenuOption
;
1771 while (Link
!= EndMenu
) {
1772 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1773 if (MenuOption
->Row
== 0) {
1774 UpdateOptionSkipLines (MenuOption
);
1776 Distance
+= MenuOption
->Skip
;
1777 Link
= Link
->BackLink
;
1783 Find the top of screen menu base on the previous record menu info.
1785 @param HighLightMenu The link_entry pointer to highlight menu.
1787 @retval Return the the link_entry pointer top of screen menu.
1791 FindTopOfScreenMenuOption (
1792 IN LIST_ENTRY
*HighLightMenu
1796 UI_MENU_OPTION
*MenuOption
;
1800 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1801 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1803 NewPos
= gMenuOption
.ForwardLink
;
1804 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1806 while (!IsTopOfScreeMenuOption(MenuOption
)) {
1807 NewPos
= NewPos
->ForwardLink
;
1808 if (NewPos
== &gMenuOption
) {
1810 // Not Found it, break
1814 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1818 // Last time top of screen menu has disappeared.
1820 if (NewPos
== &gMenuOption
) {
1824 // Check whether highlight menu and top of screen menu can be shown within one page,
1825 // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
1826 // may be dynamically inserted between highlightmenu and previous top of screen menu,
1827 // So previous record top of screen menu is not appropriate for current display.
1829 if (GetDistanceBetweenMenus (HighLightMenu
, NewPos
) + 1 > BottomRow
- TopRow
) {
1837 Find the first menu which will be show at the top.
1839 @param FormData The data info for this form.
1840 @param TopOfScreen The link_entry pointer to top menu.
1841 @param HighlightMenu The menu which will be highlight.
1842 @param SkipValue The skip value for the top menu.
1847 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1848 OUT LIST_ENTRY
**TopOfScreen
,
1849 OUT LIST_ENTRY
**HighlightMenu
,
1850 OUT UINTN
*SkipValue
1855 UI_MENU_OPTION
*MenuOption
;
1858 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1859 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1861 // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
1862 // and the other is exit current form and enter last form, it can be covered by the else case.
1864 if (gMisMatch
&& gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
&& gFormData
->FormId
== gHighligthMenuInfo
.FormId
) {
1866 // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
1867 // base on the record highlight info to find the highlight menu.
1870 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1871 if (*HighlightMenu
!= NULL
) {
1873 // Update skip info for this highlight menu.
1875 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1876 UpdateOptionSkipLines (MenuOption
);
1879 // Found the last time highlight menu.
1881 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1882 if (*TopOfScreen
!= NULL
) {
1884 // Found the last time selectable top of screen menu.
1886 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1887 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1888 UpdateOptionSkipLines (MenuOption
);
1890 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1893 // Not found last time top of screen menu, so base on current highlight menu
1894 // to find the new top of screen menu.
1895 // Make the current highlight menu at the bottom of the form to calculate the
1896 // top of screen menu.
1898 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1899 *TopOfScreen
= *HighlightMenu
;
1902 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1905 *SkipValue
= TmpValue
;
1909 // Last time highlight menu has disappear, find the first highlightable menu as the default one.
1911 *HighlightMenu
= gMenuOption
.ForwardLink
;
1912 if (!IsListEmpty (&gMenuOption
)) {
1913 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1915 *TopOfScreen
= gMenuOption
.ForwardLink
;
1919 } else if (FormData
->HighLightedStatement
!= NULL
) {
1920 if (IsSavedHighlightStatement (FormData
->HighLightedStatement
)) {
1922 // Input highlight menu is same as last time highlight menu.
1923 // Base on last time highlight menu to set the top of screen menu and highlight menu.
1925 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1926 ASSERT (*HighlightMenu
!= NULL
);
1929 // Update skip info for this highlight menu.
1931 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1932 UpdateOptionSkipLines (MenuOption
);
1934 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1935 if (*TopOfScreen
== NULL
) {
1937 // Not found last time top of screen menu, so base on current highlight menu
1938 // to find the new top of screen menu.
1939 // Make the current highlight menu at the bottom of the form to calculate the
1940 // top of screen menu.
1942 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1943 *TopOfScreen
= *HighlightMenu
;
1946 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1949 *SkipValue
= TmpValue
;
1951 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1952 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1953 UpdateOptionSkipLines (MenuOption
);
1955 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1957 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1960 // Input highlight menu is not save as last time highlight menu.
1962 *HighlightMenu
= FindHighLightMenuOption(FormData
->HighLightedStatement
);
1963 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1964 UpdateOptionSkipLines (MenuOption
);
1967 // Make the current highlight menu at the bottom of the form to calculate the
1968 // top of screen menu.
1970 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1971 *TopOfScreen
= *HighlightMenu
;
1974 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1977 *SkipValue
= TmpValue
;
1979 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1982 // If not has input highlight statement, just return the first one in this form.
1984 *TopOfScreen
= gMenuOption
.ForwardLink
;
1985 *HighlightMenu
= gMenuOption
.ForwardLink
;
1986 if (!IsListEmpty (&gMenuOption
)) {
1987 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1995 // First enter to show the menu, update highlight info.
1997 UpdateHighlightMenuInfo (*HighlightMenu
, *TopOfScreen
, *SkipValue
);
2001 Record the highlight menu and top of screen menu info.
2003 @param Highlight The menu opton which is highlight.
2004 @param TopOfScreen The menu opton which is at the top of the form.
2005 @param SkipValue The skip line info for the top of screen menu.
2009 UpdateHighlightMenuInfo (
2010 IN LIST_ENTRY
*Highlight
,
2011 IN LIST_ENTRY
*TopOfScreen
,
2015 UI_MENU_OPTION
*MenuOption
;
2016 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2018 gHighligthMenuInfo
.HiiHandle
= gFormData
->HiiHandle
;
2019 gHighligthMenuInfo
.FormId
= gFormData
->FormId
;
2020 gHighligthMenuInfo
.SkipValue
= (UINT16
)SkipValue
;
2022 if (!IsListEmpty (&gMenuOption
)) {
2023 MenuOption
= MENU_OPTION_FROM_LINK (Highlight
);
2024 Statement
= MenuOption
->ThisTag
;
2026 gUserInput
->SelectedStatement
= Statement
;
2028 gHighligthMenuInfo
.HLTSequence
= MenuOption
->Sequence
;
2029 gHighligthMenuInfo
.HLTQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
2030 if (gHighligthMenuInfo
.HLTQuestionId
== 0) {
2032 // if question id == 0, save the opcode buffer..
2034 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2035 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2037 gHighligthMenuInfo
.HLTOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2038 ASSERT (gHighligthMenuInfo
.HLTOpCode
!= NULL
);
2040 gHighligthMenuInfo
.HLTIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2043 MenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2044 Statement
= MenuOption
->ThisTag
;
2046 gHighligthMenuInfo
.TOSQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
2047 if (gHighligthMenuInfo
.TOSQuestionId
== 0) {
2049 // if question id == 0, save the opcode buffer..
2051 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2052 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2054 gHighligthMenuInfo
.TOSOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2055 ASSERT (gHighligthMenuInfo
.TOSOpCode
!= NULL
);
2057 gHighligthMenuInfo
.TOSIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2060 gUserInput
->SelectedStatement
= NULL
;
2062 gHighligthMenuInfo
.HLTSequence
= 0;
2063 gHighligthMenuInfo
.HLTQuestionId
= 0;
2064 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2065 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2067 gHighligthMenuInfo
.HLTOpCode
= NULL
;
2068 gHighligthMenuInfo
.HLTIndex
= 0;
2070 gHighligthMenuInfo
.TOSQuestionId
= 0;
2071 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2072 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2074 gHighligthMenuInfo
.TOSOpCode
= NULL
;
2075 gHighligthMenuInfo
.TOSIndex
= 0;
2080 Update attribut for this menu.
2082 @param MenuOption The menu opton which this attribut used to.
2083 @param Highlight Whether this menu will be highlight.
2087 SetDisplayAttribute (
2088 IN UI_MENU_OPTION
*MenuOption
,
2089 IN BOOLEAN Highlight
2092 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2094 Statement
= MenuOption
->ThisTag
;
2097 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2101 if (MenuOption
->GrayOut
) {
2102 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2104 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2105 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2107 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2113 Print string for this menu option.
2115 @param MenuOption The menu opton which this attribut used to.
2116 @param Col The column that this string will be print at.
2117 @param Row The row that this string will be print at.
2118 @param String The string which need to print.
2119 @param Width The width need to print, if string is less than the
2120 width, the block space will be used.
2121 @param Highlight Whether this menu will be highlight.
2126 IN UI_MENU_OPTION
*MenuOption
,
2131 IN BOOLEAN Highlight
2137 // Print string with normal color.
2140 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
2145 // Print the highlight menu string.
2146 // First print the highlight string.
2148 SetDisplayAttribute(MenuOption
, TRUE
);
2149 Length
= PrintStringAt (Col
, Row
, String
);
2152 // Second, clean the empty after the string.
2154 SetDisplayAttribute(MenuOption
, FALSE
);
2155 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
2159 Check whether this menu can has option string.
2161 @param MenuOption The menu opton which this attribut used to.
2163 @retval TRUE This menu option can have option string.
2164 @retval FALSE This menu option can't have option string.
2169 IN UI_MENU_OPTION
*MenuOption
2172 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2175 EFI_IFR_TEXT
*TestOp
;
2178 Statement
= MenuOption
->ThisTag
;
2181 // See if the second text parameter is really NULL
2183 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2184 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
2185 if (TestOp
->TextTwo
!= 0) {
2186 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
2187 Size
= StrLen (String
);
2192 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
2193 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
2194 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
2195 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
2196 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
2198 // Allow a wide display if text op-code and no secondary text op-code
2200 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
2210 Double confirm with user about the action.
2212 @param Action The user input action.
2214 @retval TRUE User confirm with the input or not need user confirm.
2215 @retval FALSE User want ignore this input.
2232 CatLen
= StrLen (gConfirmMsgConnect
);
2235 // Below action need extra popup dialog to confirm.
2237 CheckFlags
= BROWSER_ACTION_DISCARD
|
2238 BROWSER_ACTION_DEFAULT
|
2239 BROWSER_ACTION_SUBMIT
|
2240 BROWSER_ACTION_RESET
|
2241 BROWSER_ACTION_EXIT
;
2244 // Not need to confirm with user, just return TRUE.
2246 if ((Action
& CheckFlags
) == 0) {
2250 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2251 CfmStrLen
+= StrLen (gConfirmDiscardMsg
);
2254 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2255 if (CfmStrLen
!= 0) {
2256 CfmStrLen
+= CatLen
;
2259 CfmStrLen
+= StrLen (gConfirmDefaultMsg
);
2262 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2263 if (CfmStrLen
!= 0) {
2264 CfmStrLen
+= CatLen
;
2267 CfmStrLen
+= StrLen (gConfirmSubmitMsg
);
2270 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2271 if (CfmStrLen
!= 0) {
2272 CfmStrLen
+= CatLen
;
2275 CfmStrLen
+= StrLen (gConfirmResetMsg
);
2278 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2279 if (CfmStrLen
!= 0) {
2280 CfmStrLen
+= CatLen
;
2283 CfmStrLen
+= StrLen (gConfirmExitMsg
);
2287 // Allocate buffer to save the string.
2288 // String + "?" + "\0"
2290 MaxLen
= CfmStrLen
+ 1 + 1;
2291 CfmStr
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
2292 ASSERT (CfmStr
!= NULL
);
2294 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2295 StrCpyS (CfmStr
, MaxLen
, gConfirmDiscardMsg
);
2298 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2299 if (CfmStr
[0] != 0) {
2300 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2301 StrCatS (CfmStr
, MaxLen
, gConfirmDefaultMsg2nd
);
2303 StrCpyS (CfmStr
, MaxLen
, gConfirmDefaultMsg
);
2307 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2308 if (CfmStr
[0] != 0) {
2309 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2310 StrCatS (CfmStr
, MaxLen
, gConfirmSubmitMsg2nd
);
2312 StrCpyS (CfmStr
, MaxLen
, gConfirmSubmitMsg
);
2316 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2317 if (CfmStr
[0] != 0) {
2318 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2319 StrCatS (CfmStr
, MaxLen
, gConfirmResetMsg2nd
);
2321 StrCpyS (CfmStr
, MaxLen
, gConfirmResetMsg
);
2325 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2326 if (CfmStr
[0] != 0) {
2327 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2328 StrCatS (CfmStr
, MaxLen
, gConfirmExitMsg2nd
);
2330 StrCpyS (CfmStr
, MaxLen
, gConfirmExitMsg
);
2334 StrCatS (CfmStr
, MaxLen
, gConfirmMsgEnd
);
2337 CreateDialog (&Key
, gEmptyString
, CfmStr
, gConfirmOpt
, gEmptyString
, NULL
);
2338 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2339 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptNo
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2340 (Key
.ScanCode
!= SCAN_ESC
));
2342 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) {
2354 Print string for this menu option.
2356 @param MenuOption The menu opton which this attribut used to.
2357 @param SkipWidth The skip width between the left to the start of the prompt.
2358 @param BeginCol The begin column for one menu.
2359 @param SkipLine The skip line for this menu.
2360 @param BottomRow The bottom row for this form.
2361 @param Highlight Whether this menu will be highlight.
2362 @param UpdateCol Whether need to update the column info for Date/Time.
2364 @retval EFI_SUCESSS Process the user selection success.
2369 IN UI_MENU_OPTION
*MenuOption
,
2374 IN BOOLEAN Highlight
,
2375 IN BOOLEAN UpdateCol
2378 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2383 CHAR16
*OptionString
;
2384 CHAR16
*OutputString
;
2391 BOOLEAN IsProcessingFirstRow
;
2393 UINTN PromptLineNum
;
2394 UINTN OptionLineNum
;
2398 Statement
= MenuOption
->ThisTag
;
2406 IsProcessingFirstRow
= TRUE
;
2409 // Set default color.
2411 SetDisplayAttribute (MenuOption
, FALSE
);
2414 // 1. Paint the option string.
2416 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
2417 if (EFI_ERROR (Status
)) {
2421 if (OptionString
!= NULL
) {
2422 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2424 // Adjust option string for date/time opcode.
2426 ProcessStringForDateTime(MenuOption
, OptionString
, UpdateCol
);
2429 Width
= (UINT16
) gOptionBlockWidth
- 1;
2430 Row
= MenuOption
->Row
;
2434 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2435 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
2436 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2438 // For date/time question, it has three menu options for this qustion.
2439 // The first/second menu options with the skip value is 0. the last one
2440 // with skip value is 1.
2442 if (MenuOption
->Skip
!= 0) {
2444 // For date/ time, print the last past (year for date and second for time)
2445 // - 7 means skip [##/##/ for date and [##:##: for time.
2447 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
2450 // For date/ time, print the first and second past (year for date and second for time)
2451 // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
2452 // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
2453 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
) - 1, Highlight
);
2456 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2462 // If there is more string to process print on the next row and increment the Skip value
2464 if (StrLen (&OptionString
[Index
]) != 0) {
2468 // Since the Number of lines for this menu entry may or may not be reflected accurately
2469 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2470 // some testing to ensure we are keeping this in-sync.
2472 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2474 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2480 FreePool (OutputString
);
2488 FreePool (OptionString
);
2492 // 2. Paint the description.
2494 PromptWidth
= GetWidth (MenuOption
, &AdjustValue
);
2495 Row
= MenuOption
->Row
;
2499 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
2500 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
2503 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2504 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2506 // 1.Clean the start LEFT_SKIPPED_COLUMNS
2508 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
2510 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2 && IsProcessingFirstRow
) {
2512 // Print Arrow for Goto button.
2515 MenuOption
->Col
- 2,
2517 GEOMETRICSHAPE_RIGHT_TRIANGLE
2519 IsProcessingFirstRow
= FALSE
;
2521 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
2525 // If there is more string to process print on the next row and increment the Skip value
2527 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2533 FreePool (OutputString
);
2544 // 3. If this is a text op with secondary text information
2546 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
2547 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
2549 Width
= (UINT16
) gOptionBlockWidth
- 1;
2550 Row
= MenuOption
->Row
;
2554 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2555 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
2556 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2560 // If there is more string to process print on the next row and increment the Skip value
2562 if (StrLen (&StringPtr
[Index
]) != 0) {
2566 // If the rows for text two is greater than or equal to the skip value, increase the skip value
2568 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2574 FreePool (OutputString
);
2580 FreePool (StringPtr
);
2584 // 4.Line number for Option string and prompt string are not equal.
2585 // Clean the column whose line number is less.
2587 if (HasOptionString(MenuOption
) && (OptionLineNum
!= PromptLineNum
)) {
2588 Col
= OptionLineNum
< PromptLineNum
? MenuOption
->OptCol
: BeginCol
;
2589 Row
= (OptionLineNum
< PromptLineNum
? OptionLineNum
: PromptLineNum
) + MenuOption
->Row
;
2590 Width
= (UINT16
) (OptionLineNum
< PromptLineNum
? gOptionBlockWidth
: PromptWidth
+ AdjustValue
+ SkipWidth
);
2591 MaxRow
= (OptionLineNum
< PromptLineNum
? PromptLineNum
: OptionLineNum
) + MenuOption
->Row
- 1;
2593 while (Row
<= MaxRow
) {
2594 DisplayMenuString (MenuOption
, Col
, Row
++, L
"", Width
, FALSE
);
2602 Display menu and wait for user to select one menu option, then return it.
2603 If AutoBoot is enabled, then if user doesn't select any option,
2604 after period of time, it will automatically return the first menu option.
2606 @param FormData The current form data info.
2608 @retval EFI_SUCESSS Process the user selection success.
2609 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
2614 IN FORM_DISPLAY_ENGINE_FORM
*FormData
2619 UINTN DistanceValue
;
2628 CHAR16
*StringRightPtr
;
2629 CHAR16
*StringErrorPtr
;
2630 CHAR16
*OptionString
;
2632 CHAR16
*HelpHeaderString
;
2633 CHAR16
*HelpBottomString
;
2642 LIST_ENTRY
*TopOfScreen
;
2643 LIST_ENTRY
*SavedListEntry
;
2644 UI_MENU_OPTION
*MenuOption
;
2645 UI_MENU_OPTION
*NextMenuOption
;
2646 UI_MENU_OPTION
*SavedMenuOption
;
2647 UI_CONTROL_FLAG ControlFlag
;
2648 UI_SCREEN_OPERATION ScreenOperation
;
2649 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2650 BROWSER_HOT_KEY
*HotKey
;
2651 UINTN HelpPageIndex
;
2652 UINTN HelpPageCount
;
2655 UINTN HelpHeaderLine
;
2656 UINTN HelpBottomLine
;
2657 BOOLEAN MultiHelpPage
;
2658 UINT16 EachLineWidth
;
2659 UINT16 HeaderLineWidth
;
2660 UINT16 BottomLineWidth
;
2661 EFI_STRING_ID HelpInfo
;
2662 UI_EVENT_TYPE EventType
;
2663 BOOLEAN SkipHighLight
;
2664 EFI_HII_VALUE
*StatementValue
;
2666 EventType
= UIEventNone
;
2667 Status
= EFI_SUCCESS
;
2669 HelpHeaderString
= NULL
;
2670 HelpBottomString
= NULL
;
2671 OptionString
= NULL
;
2672 ScreenOperation
= UiNoOperation
;
2680 MultiHelpPage
= FALSE
;
2682 HeaderLineWidth
= 0;
2683 BottomLineWidth
= 0;
2687 SkipHighLight
= FALSE
;
2689 NextMenuOption
= NULL
;
2690 SavedMenuOption
= NULL
;
2694 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
2696 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2698 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
2699 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
2702 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2703 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
2705 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2708 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
2709 if (!IsListEmpty (&gMenuOption
)) {
2710 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2711 gUserInput
->SelectedStatement
= NextMenuOption
->ThisTag
;
2714 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2716 ControlFlag
= CfInitialization
;
2718 switch (ControlFlag
) {
2719 case CfInitialization
:
2720 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
2721 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
2723 // Clear Statement range if different formset is painted.
2726 gStatementDimensions
.LeftColumn
,
2727 gStatementDimensions
.RightColumn
,
2728 TopRow
- SCROLL_ARROW_HEIGHT
,
2729 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2730 GetFieldTextColor ()
2734 ControlFlag
= CfRepaint
;
2738 ControlFlag
= CfRefreshHighLight
;
2748 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2751 // 1. Check whether need to print the arrow up.
2753 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2757 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2758 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2760 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2763 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2765 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2766 TopRow
- SCROLL_ARROW_HEIGHT
,
2769 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2773 // 2.Paint the menu.
2775 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2776 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2777 MenuOption
->Row
= Row
;
2778 MenuOption
->Col
= Col
;
2779 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2780 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2782 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2785 if (MenuOption
->NestInStatement
) {
2786 MenuOption
->Col
+= SUBTITLE_INDENT
;
2790 // Save the highlight menu, will be used in CfRefreshHighLight case.
2792 if (Link
== NewPos
) {
2793 SavedMenuOption
= MenuOption
;
2794 SkipHighLight
= TRUE
;
2797 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2798 Status
= DisplayOneMenu (MenuOption
,
2799 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2800 gStatementDimensions
.LeftColumn
+ gModalSkipColumn
,
2801 Link
== TopOfScreen
? SkipValue
: 0,
2803 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2807 Status
= DisplayOneMenu (MenuOption
,
2808 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2809 gStatementDimensions
.LeftColumn
,
2810 Link
== TopOfScreen
? SkipValue
: 0,
2812 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2817 if (EFI_ERROR (Status
)) {
2825 // 3. Update the row info which will be used by next menu.
2827 if (Link
== TopOfScreen
) {
2828 Row
+= MenuOption
->Skip
- SkipValue
;
2830 Row
+= MenuOption
->Skip
;
2833 if (Row
> BottomRow
) {
2834 if (!ValueIsScroll (FALSE
, Link
)) {
2838 Row
= BottomRow
+ 1;
2844 // 3. Menus in this form may not cover all form, clean the remain field.
2846 while (Row
<= BottomRow
) {
2847 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2848 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2850 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2855 // 4. Print the down arrow row.
2857 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2858 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * + gModalSkipColumn
);
2860 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2863 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2865 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2866 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2869 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2876 case CfRefreshHighLight
:
2879 // MenuOption: Last menu option that need to remove hilight
2880 // MenuOption is set to NULL in Repaint
2881 // NewPos: Current menu option that need to hilight
2883 ControlFlag
= CfUpdateHelpString
;
2885 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
2887 if (SkipHighLight
) {
2888 SkipHighLight
= FALSE
;
2889 MenuOption
= SavedMenuOption
;
2890 RefreshKeyHelp(gFormData
, SavedMenuOption
->ThisTag
, FALSE
);
2894 if (IsListEmpty (&gMenuOption
)) {
2896 // No menu option, just update the hotkey filed.
2898 RefreshKeyHelp(gFormData
, NULL
, FALSE
);
2902 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2907 if (NewPos
== TopOfScreen
) {
2913 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2914 if (MenuOption
!= NULL
) {
2916 // Remove the old highlight menu.
2918 Status
= DisplayOneMenu (MenuOption
,
2919 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2920 gStatementDimensions
.LeftColumn
,
2929 // This is the current selected statement
2931 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2932 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2934 if (!IsSelectable (MenuOption
)) {
2938 Status
= DisplayOneMenu (MenuOption
,
2939 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2940 gStatementDimensions
.LeftColumn
,
2949 case CfUpdateHelpString
:
2950 ControlFlag
= CfPrepareToReadKey
;
2951 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2956 // NewLine means only update highlight menu (remove old highlight and highlith
2957 // the new one), not need to full repain the form.
2959 if (Repaint
|| NewLine
) {
2960 if (IsListEmpty (&gMenuOption
)) {
2962 // Don't print anything if no mwnu option.
2964 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2967 // Don't print anything if it is a NULL help token
2969 ASSERT(MenuOption
!= NULL
);
2970 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2971 Statement
= MenuOption
->ThisTag
;
2972 StatementValue
= &Statement
->CurrentValue
;
2973 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2974 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)){
2975 StringPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2977 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2980 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)){
2981 StringRightPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2982 StringErrorPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2983 StringPtr
= AllocateZeroPool ((StrLen (StringRightPtr
) + StrLen (StringErrorPtr
)+ 1 ) * sizeof (CHAR16
));
2984 StrCpyS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringRightPtr
);
2985 StrCatS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringErrorPtr
);
2986 FreePool (StringRightPtr
);
2987 FreePool (StringErrorPtr
);
2989 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2994 RowCount
= BottomRow
- TopRow
+ 1;
2997 // 1.Calculate how many line the help string need to print.
2999 if (HelpString
!= NULL
) {
3000 FreePool (HelpString
);
3003 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
3004 FreePool (StringPtr
);
3006 if (HelpLine
> RowCount
) {
3007 MultiHelpPage
= TRUE
;
3008 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
3009 if (HelpHeaderString
!= NULL
) {
3010 FreePool (HelpHeaderString
);
3011 HelpHeaderString
= NULL
;
3013 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
3014 FreePool (StringPtr
);
3015 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
3016 if (HelpBottomString
!= NULL
) {
3017 FreePool (HelpBottomString
);
3018 HelpBottomString
= NULL
;
3020 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
3021 FreePool (StringPtr
);
3023 // Calculate the help page count.
3025 if (HelpLine
> 2 * RowCount
- 2) {
3026 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
3027 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) != 0) {
3034 MultiHelpPage
= FALSE
;
3039 // Check whether need to show the 'More(U/u)' at the begin.
3040 // Base on current direct info, here shows aligned to the right side of the column.
3041 // If the direction is multi line and aligned to right side may have problem, so
3042 // add ASSERT code here.
3044 if (HelpPageIndex
> 0) {
3045 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3046 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
3047 ASSERT (HelpHeaderLine
== 1);
3048 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3049 PrintStringAtWithWidth (
3050 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3056 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
3058 &HelpHeaderString
[Index
* HeaderLineWidth
]
3063 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
3065 // Print the help string info.
3067 if (!MultiHelpPage
) {
3068 for (Index
= 0; Index
< HelpLine
; Index
++) {
3069 PrintStringAtWithWidth (
3070 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3072 &HelpString
[Index
* EachLineWidth
],
3076 for (; Index
< RowCount
; Index
++) {
3077 PrintStringAtWithWidth (
3078 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3084 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3086 if (HelpPageIndex
== 0) {
3087 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
3088 PrintStringAtWithWidth (
3089 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3091 &HelpString
[Index
* EachLineWidth
],
3096 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
3097 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
3098 PrintStringAtWithWidth (
3099 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3100 Index
+ TopRow
+ HelpHeaderLine
,
3101 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
3105 if (HelpPageIndex
== HelpPageCount
- 1) {
3106 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
3107 PrintStringAtWithWidth (
3108 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3109 Index
+ TopRow
+ HelpHeaderLine
,
3114 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3120 // Check whether need to print the 'More(D/d)' at the bottom.
3121 // Base on current direct info, here shows aligned to the right side of the column.
3122 // If the direction is multi line and aligned to right side may have problem, so
3123 // add ASSERT code here.
3125 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
3126 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3127 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
3128 ASSERT (HelpBottomLine
== 1);
3129 ASSERT (GetStringWidth (HelpBottomString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3130 PrintStringAtWithWidth (
3131 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3132 BottomRow
+ Index
- HelpBottomLine
+ 1,
3137 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
3138 BottomRow
+ Index
- HelpBottomLine
+ 1,
3139 &HelpBottomString
[Index
* BottomLineWidth
]
3144 // Reset this flag every time we finish using it.
3150 case CfPrepareToReadKey
:
3151 ControlFlag
= CfReadKey
;
3152 ScreenOperation
= UiNoOperation
;
3156 ControlFlag
= CfScreenOperation
;
3159 // Wait for user's selection
3162 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3163 if (!EFI_ERROR (Status
)) {
3164 EventType
= UIEventKey
;
3169 // If we encounter error, continue to read another key in.
3171 if (Status
!= EFI_NOT_READY
) {
3175 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
3176 if (EventType
== UIEventKey
) {
3177 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3182 if (EventType
== UIEventDriver
) {
3184 gUserInput
->Action
= BROWSER_ACTION_NONE
;
3185 ControlFlag
= CfExit
;
3189 if (EventType
== UIEventTimeOut
) {
3190 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3191 ControlFlag
= CfExit
;
3195 switch (Key
.UnicodeChar
) {
3196 case CHAR_CARRIAGE_RETURN
:
3197 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3198 ControlFlag
= CfReadKey
;
3202 ScreenOperation
= UiSelect
;
3207 // We will push the adjustment of these numeric values directly to the input handler
3208 // NOTE: we won't handle manual input numeric
3213 // If the screen has no menu items, and the user didn't select UiReset
3214 // ignore the selection and go back to reading keys.
3216 ASSERT(MenuOption
!= NULL
);
3217 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3218 ControlFlag
= CfReadKey
;
3222 Statement
= MenuOption
->ThisTag
;
3223 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
3224 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3225 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
3227 if (Key
.UnicodeChar
== '+') {
3228 gDirection
= SCAN_RIGHT
;
3230 gDirection
= SCAN_LEFT
;
3233 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3234 if (OptionString
!= NULL
) {
3235 FreePool (OptionString
);
3237 if (EFI_ERROR (Status
)) {
3239 // Repaint to clear possible error prompt pop-up
3244 ControlFlag
= CfExit
;
3250 ScreenOperation
= UiUp
;
3255 ScreenOperation
= UiDown
;
3259 if(IsListEmpty (&gMenuOption
)) {
3260 ControlFlag
= CfReadKey
;
3264 ASSERT(MenuOption
!= NULL
);
3265 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3266 ScreenOperation
= UiSelect
;
3272 if (!MultiHelpPage
) {
3273 ControlFlag
= CfReadKey
;
3276 ControlFlag
= CfUpdateHelpString
;
3277 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3282 if (!MultiHelpPage
) {
3283 ControlFlag
= CfReadKey
;
3286 ControlFlag
= CfUpdateHelpString
;
3287 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3291 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3292 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3293 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3298 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3300 // ModalForm has no ESC key and Hot Key.
3302 ControlFlag
= CfReadKey
;
3303 } else if (Index
== mScanCodeNumber
) {
3305 // Check whether Key matches the registered hot key.
3308 HotKey
= GetHotKeyFromRegisterList (&Key
);
3309 if (HotKey
!= NULL
) {
3310 ScreenOperation
= UiHotKey
;
3317 case CfScreenOperation
:
3318 if ((ScreenOperation
!= UiReset
) && (ScreenOperation
!= UiHotKey
)) {
3320 // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
3321 // ignore the selection and go back to reading keys.
3323 if (IsListEmpty (&gMenuOption
)) {
3324 ControlFlag
= CfReadKey
;
3330 Index
< ARRAY_SIZE (gScreenOperationToControlFlag
);
3333 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3334 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3341 ControlFlag
= CfRepaint
;
3343 ASSERT(MenuOption
!= NULL
);
3344 Statement
= MenuOption
->ThisTag
;
3345 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
3349 switch (Statement
->OpCode
->OpCode
) {
3350 case EFI_IFR_REF_OP
:
3351 case EFI_IFR_ACTION_OP
:
3352 case EFI_IFR_RESET_BUTTON_OP
:
3353 ControlFlag
= CfExit
;
3358 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3360 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
3361 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3363 if (OptionString
!= NULL
) {
3364 FreePool (OptionString
);
3367 if (EFI_ERROR (Status
)) {
3370 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
3373 ControlFlag
= CfExit
;
3381 // We come here when someone press ESC
3382 // If the policy is not exit front page when user press ESC, process here.
3384 if (!FormExitPolicy()) {
3387 ControlFlag
= CfRepaint
;
3391 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3392 ControlFlag
= CfExit
;
3396 ControlFlag
= CfRepaint
;
3398 ASSERT (HotKey
!= NULL
);
3400 if (FxConfirmPopup(HotKey
->Action
)) {
3401 gUserInput
->Action
= HotKey
->Action
;
3402 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3403 gUserInput
->DefaultId
= HotKey
->DefaultId
;
3405 ControlFlag
= CfExit
;
3409 ControlFlag
= CfRepaint
;
3415 ControlFlag
= CfRepaint
;
3416 ASSERT(MenuOption
!= NULL
);
3417 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3418 if (MenuOption
->Sequence
!= 0) {
3420 // In the middle or tail of the Date/Time op-code set, go left.
3422 ASSERT(NewPos
!= NULL
);
3423 NewPos
= NewPos
->BackLink
;
3429 ControlFlag
= CfRepaint
;
3430 ASSERT(MenuOption
!= NULL
);
3431 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3432 if (MenuOption
->Sequence
!= 2) {
3434 // In the middle or tail of the Date/Time op-code set, go left.
3436 ASSERT(NewPos
!= NULL
);
3437 NewPos
= NewPos
->ForwardLink
;
3443 ControlFlag
= CfRepaint
;
3446 SavedListEntry
= NewPos
;
3447 ASSERT(NewPos
!= NULL
);
3449 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3450 ASSERT (MenuOption
!= NULL
);
3453 // Adjust Date/Time position before we advance forward.
3455 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3457 NewPos
= NewPos
->BackLink
;
3459 // Find next selectable menu or the first menu beyond current form.
3461 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
, FALSE
);
3462 if (Difference
< 0) {
3464 // We hit the begining MenuOption that can be focused
3465 // so we simply scroll to the top.
3468 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3469 TopOfScreen
= gMenuOption
.ForwardLink
;
3470 NewPos
= SavedListEntry
;
3474 // Scroll up to the last page when we have arrived at top page.
3476 TopOfScreen
= FindTopOfScreenMenu (gMenuOption
.BackLink
, BottomRow
- TopRow
, &SkipValue
);
3477 NewPos
= gMenuOption
.BackLink
;
3478 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3481 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3483 if (MenuOption
->Row
< TopRow
+ Difference
+ NextMenuOption
->Skip
) {
3485 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3487 TopOfScreen
= NewPos
;
3493 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3495 // BottomRow - TopRow + 1 means the total rows current forms supported.
3496 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3497 // and new top menu. New top menu will all shows in next form, but last highlight menu
3498 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3499 // last highlight menu.
3501 if (!IsSelectable(NextMenuOption
) && IsSelectable(MenuOption
) &&
3502 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3503 NewPos
= SavedListEntry
;
3507 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3510 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3512 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3513 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3515 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3520 // SkipValue means lines is skipped when show the top menu option.
3522 ControlFlag
= CfRepaint
;
3528 // First minus the menu of the top screen, it's value is SkipValue.
3530 if (SkipValue
>= BottomRow
- TopRow
+ 1) {
3532 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
3533 // form of options to be show, so just update the SkipValue to show the next
3534 // parts of options.
3536 SkipValue
-= BottomRow
- TopRow
+ 1;
3537 NewPos
= TopOfScreen
;
3540 Index
= (BottomRow
+ 1) - SkipValue
- TopRow
;
3543 TopOfScreen
= FindTopOfScreenMenu(TopOfScreen
, Index
, &SkipValue
);
3544 NewPos
= TopOfScreen
;
3545 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, FALSE
);
3547 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3550 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3551 // Don't do this when we are already in the first page.
3553 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3554 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3556 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3561 // SkipValue means lines is skipped when show the top menu option.
3563 ControlFlag
= CfRepaint
;
3568 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3569 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
3571 // Count to the menu option which will show at the top of the next form.
3573 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
3574 Link
= Link
->ForwardLink
;
3575 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3576 Index
= Index
+ NextMenuOption
->Skip
;
3579 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
3581 // Highlight on the last menu which can be highlight.
3584 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
, TRUE
);
3587 // Calculate the skip line for top of screen menu.
3589 if (Link
== TopOfScreen
) {
3591 // The top of screen menu option occupies the entire form.
3593 SkipValue
+= BottomRow
- TopRow
+ 1;
3595 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3600 // Move to the Next selectable menu.
3602 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
, TRUE
);
3606 // Save the menu as the next highlight menu.
3610 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3613 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3614 // Don't do this when we are already in the last page.
3616 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3617 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3619 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3624 // SkipValue means lines is skipped when show the top menu option.
3625 // NewPos points to the menu which is highlighted now.
3627 ControlFlag
= CfRepaint
;
3630 if (NewPos
== TopOfScreen
) {
3636 SavedListEntry
= NewPos
;
3638 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3639 // to be one that progresses to the next set of op-codes, we need to advance to the last
3640 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3641 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3642 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3643 // the Date/Time op-code.
3645 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3647 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3648 NewPos
= NewPos
->ForwardLink
;
3650 // Find the next selectable menu.
3652 if (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
> BottomRow
+ 1) {
3653 if (gMenuOption
.ForwardLink
== NewPos
|| &gMenuOption
== NewPos
) {
3659 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
+ 1 - (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
), FALSE
);
3661 if (Difference
< 0) {
3663 // Scroll to the first page.
3665 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3666 TopOfScreen
= gMenuOption
.ForwardLink
;
3670 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3672 NewPos
= gMenuOption
.ForwardLink
;
3673 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3677 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3679 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3680 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3682 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3687 // Get next selected menu info.
3689 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3690 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3691 if (NextMenuOption
->Row
== 0) {
3692 UpdateOptionSkipLines (NextMenuOption
);
3696 // Calculate new highlight menu end row.
3698 Temp
= (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
) + Difference
+ NextMenuOption
->Skip
- 1;
3699 if (Temp
> BottomRow
) {
3701 // Get the top screen menu info.
3703 AdjustDateAndTimePosition (FALSE
, &TopOfScreen
);
3704 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3707 // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
3708 // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
3710 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3712 // Skip the top op-code
3714 TopOfScreen
= TopOfScreen
->ForwardLink
;
3715 DistanceValue
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3717 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3720 // If we have a remainder, skip that many more op-codes until we drain the remainder
3721 // Special case is the selected highlight menu has more than one form of menus.
3723 while (DistanceValue
>= SavedMenuOption
->Skip
&& TopOfScreen
!= NewPos
) {
3725 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3727 DistanceValue
= DistanceValue
- (INTN
) SavedMenuOption
->Skip
;
3728 TopOfScreen
= TopOfScreen
->ForwardLink
;
3729 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3732 // Since we will act on this op-code in the next routine, and increment the
3733 // SkipValue, set the skips to one less than what is required.
3735 if (TopOfScreen
!= NewPos
) {
3736 SkipValue
= DistanceValue
;
3742 // Since we will act on this op-code in the next routine, and increment the
3743 // SkipValue, set the skips to one less than what is required.
3745 SkipValue
+= Temp
- BottomRow
;
3748 } else if (!IsSelectable (NextMenuOption
)) {
3750 // Continue to go down until scroll to next page or the selectable option is found.
3752 ScreenOperation
= UiDown
;
3753 ControlFlag
= CfScreenOperation
;
3757 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3760 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3762 // BottomRow - TopRow + 1 means the total rows current forms supported.
3763 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3764 // and new top menu. New top menu will all shows in next form, but last highlight menu
3765 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3766 // last highlight menu.
3768 if (!IsSelectable (NextMenuOption
) && IsSelectable (MenuOption
) &&
3769 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3770 NewPos
= SavedListEntry
;
3773 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3776 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3778 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3779 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3781 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3784 case CfUiNoOperation
:
3785 ControlFlag
= CfRepaint
;
3789 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3790 if (HelpString
!= NULL
) {
3791 FreePool (HelpString
);
3793 if (HelpHeaderString
!= NULL
) {
3794 FreePool (HelpHeaderString
);
3796 if (HelpBottomString
!= NULL
) {
3797 FreePool (HelpBottomString
);
3808 Free the UI Menu Option structure data.
3810 @param MenuOptionList Point to the menu option list which need to be free.
3815 LIST_ENTRY
*MenuOptionList
3819 UI_MENU_OPTION
*Option
;
3822 // Free menu option list
3824 while (!IsListEmpty (MenuOptionList
)) {
3825 Link
= GetFirstNode (MenuOptionList
);
3826 Option
= MENU_OPTION_FROM_LINK (Link
);
3827 if (Option
->Description
!= NULL
){
3828 FreePool(Option
->Description
);
3830 RemoveEntryList (&Option
->Link
);
3837 Base on the browser status info to show an pop up message.
3841 BrowserStatusProcess (
3847 EFI_EVENT WaitList
[2];
3848 EFI_EVENT RefreshIntervalEvent
;
3849 EFI_EVENT TimeOutEvent
;
3853 WARNING_IF_CONTEXT EventContext
;
3854 EFI_IFR_OP_HEADER
*OpCodeBuf
;
3855 EFI_STRING_ID StringToken
;
3856 CHAR16 DiscardChange
;
3857 CHAR16 JumpToFormSet
;
3858 CHAR16
*PrintString
;
3860 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3865 TimeOutEvent
= NULL
;
3866 RefreshIntervalEvent
= NULL
;
3868 if (gFormData
->HighLightedStatement
!= NULL
) {
3869 OpCodeBuf
= gFormData
->HighLightedStatement
->OpCode
;
3872 if (gFormData
->BrowserStatus
== (BROWSER_WARNING_IF
)) {
3873 ASSERT (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_WARNING_IF_OP
);
3875 TimeOut
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->TimeOut
;
3876 StringToken
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->Warning
;
3879 if ((gFormData
->BrowserStatus
== (BROWSER_NO_SUBMIT_IF
)) &&
3880 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_NO_SUBMIT_IF_OP
)) {
3881 StringToken
= ((EFI_IFR_NO_SUBMIT_IF
*) OpCodeBuf
)->Error
;
3882 } else if ((gFormData
->BrowserStatus
== (BROWSER_INCONSISTENT_IF
)) &&
3883 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_INCONSISTENT_IF_OP
)) {
3884 StringToken
= ((EFI_IFR_INCONSISTENT_IF
*) OpCodeBuf
)->Error
;
3888 if (StringToken
!= 0) {
3889 ErrorInfo
= GetToken (StringToken
, gFormData
->HiiHandle
);
3890 } else if (gFormData
->ErrorString
!= NULL
) {
3892 // Only used to compatible with old setup browser.
3893 // Not use this field in new browser core.
3895 ErrorInfo
= gFormData
->ErrorString
;
3897 switch (gFormData
->BrowserStatus
) {
3898 case BROWSER_SUBMIT_FAIL
:
3899 ErrorInfo
= gSaveFailed
;
3902 case BROWSER_FORM_NOT_FOUND
:
3903 ErrorInfo
= gFormNotFound
;
3906 case BROWSER_FORM_SUPPRESS
:
3907 ErrorInfo
= gFormSuppress
;
3910 case BROWSER_PROTOCOL_NOT_FOUND
:
3911 ErrorInfo
= gProtocolNotFound
;
3914 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3915 ErrorInfo
= gNoSubmitIfFailed
;
3918 case BROWSER_RECONNECT_FAIL
:
3919 ErrorInfo
= gReconnectFail
;
3922 case BROWSER_RECONNECT_SAVE_CHANGES
:
3923 ErrorInfo
= gReconnectConfirmChanges
;
3926 case BROWSER_RECONNECT_REQUIRED
:
3927 ErrorInfo
= gReconnectRequired
;
3931 ErrorInfo
= gBrowserError
;
3936 switch (gFormData
->BrowserStatus
) {
3937 case BROWSER_SUBMIT_FAIL
:
3938 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3939 case BROWSER_RECONNECT_SAVE_CHANGES
:
3940 ASSERT (gUserInput
!= NULL
);
3941 if (gFormData
->BrowserStatus
== (BROWSER_SUBMIT_FAIL
)) {
3942 PrintString
= gSaveProcess
;
3943 JumpToFormSet
= gJumpToFormSet
[0];
3944 DiscardChange
= gDiscardChange
[0];
3945 } else if (gFormData
->BrowserStatus
== (BROWSER_RECONNECT_SAVE_CHANGES
)){
3946 PrintString
= gChangesOpt
;
3947 JumpToFormSet
= gConfirmOptYes
[0];
3948 DiscardChange
= gConfirmOptNo
[0];
3950 PrintString
= gSaveNoSubmitProcess
;
3951 JumpToFormSet
= gCheckError
[0];
3952 DiscardChange
= gDiscardChange
[0];
3956 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, PrintString
, gEmptyString
, NULL
);
3957 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) &&
3958 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (JumpToFormSet
| UPPER_LOWER_CASE_OFFSET
)));
3960 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) {
3961 gUserInput
->Action
= BROWSER_ACTION_DISCARD
;
3963 gUserInput
->Action
= BROWSER_ACTION_GOTO
;
3970 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3971 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3973 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
3974 ASSERT_EFI_ERROR (Status
);
3976 EventContext
.SyncEvent
= TimeOutEvent
;
3977 EventContext
.TimeOut
= &TimeOut
;
3978 EventContext
.ErrorInfo
= ErrorInfo
;
3980 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
3981 ASSERT_EFI_ERROR (Status
);
3984 // Show the dialog first to avoid long time not reaction.
3986 gBS
->SignalEvent (RefreshIntervalEvent
);
3988 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
3989 ASSERT_EFI_ERROR (Status
);
3992 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3993 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3997 if (Status
!= EFI_NOT_READY
) {
4001 WaitList
[0] = TimeOutEvent
;
4002 WaitList
[1] = gST
->ConIn
->WaitForKey
;
4004 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
4005 ASSERT_EFI_ERROR (Status
);
4009 // Timeout occur, close the hoot time out event.
4015 gBS
->CloseEvent (TimeOutEvent
);
4016 gBS
->CloseEvent (RefreshIntervalEvent
);
4021 if (StringToken
!= 0) {
4022 FreePool (ErrorInfo
);
4027 Display one form, and return user input.
4029 @param FormData Form Data to be shown.
4030 @param UserInputData User input data.
4032 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
4033 2.Error info has show and return.
4034 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
4035 @retval EFI_NOT_FOUND New form data has some error.
4040 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
4041 OUT USER_INPUT
*UserInputData
4046 ASSERT (FormData
!= NULL
);
4047 if (FormData
== NULL
) {
4048 return EFI_INVALID_PARAMETER
;
4051 gUserInput
= UserInputData
;
4052 gFormData
= FormData
;
4055 // Process the status info first.
4057 BrowserStatusProcess();
4058 if (gFormData
->BrowserStatus
!= BROWSER_SUCCESS
) {
4060 // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
4065 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
4066 if (EFI_ERROR (Status
)) {
4071 // Global Widths should be initialized before any MenuOption creation
4072 // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
4076 // |<-.->|<-.........->|<- .........->|<-...........->|
4077 // Skip Prompt Option Help
4079 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3) + 1;
4080 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- 1 - LEFT_SKIPPED_COLUMNS
);
4081 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gOptionBlockWidth
- 1) - 1);
4083 ConvertStatementToMenu();
4086 // Check whether layout is changed.
4089 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
4090 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
4091 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
4092 mStatementLayoutIsChanged
= TRUE
;
4094 mStatementLayoutIsChanged
= FALSE
;
4097 Status
= UiDisplayMenu(FormData
);
4100 // Backup last form info.
4102 mIsFirstForm
= FALSE
;
4103 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
4104 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
4105 gOldFormEntry
.FormId
= FormData
->FormId
;
4108 //Free the Ui menu option list.
4110 FreeMenuOptionData(&gMenuOption
);
4116 Clear Screen to the initial state.
4120 DriverClearDisplayPage (
4124 ClearDisplayPage ();
4125 mIsFirstForm
= TRUE
;
4129 Set Buffer to Value for Size bytes.
4131 @param Buffer Memory to set.
4132 @param Size Number of bytes to set
4133 @param Value Value of the set operation.
4146 while ((Size
--) != 0) {
4152 Initialize Setup Browser driver.
4154 @param ImageHandle The image handle.
4155 @param SystemTable The system table.
4157 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
4158 @return Other value if failed to initialize the Setup Browser module.
4163 InitializeDisplayEngine (
4164 IN EFI_HANDLE ImageHandle
,
4165 IN EFI_SYSTEM_TABLE
*SystemTable
4169 EFI_INPUT_KEY HotKey
;
4170 EFI_STRING NewString
;
4171 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
4174 // Publish our HII data
4176 gHiiHandle
= HiiAddPackages (
4177 &gDisplayEngineGuid
,
4179 DisplayEngineStrings
,
4182 ASSERT (gHiiHandle
!= NULL
);
4185 // Install Form Display protocol
4187 Status
= gBS
->InstallProtocolInterface (
4188 &mPrivateData
.Handle
,
4189 &gEdkiiFormDisplayEngineProtocolGuid
,
4190 EFI_NATIVE_INTERFACE
,
4191 &mPrivateData
.FromDisplayProt
4193 ASSERT_EFI_ERROR (Status
);
4196 // Install HII Popup Protocol.
4198 Status
= gBS
->InstallProtocolInterface (
4199 &mPrivateData
.Handle
,
4200 &gEfiHiiPopupProtocolGuid
,
4201 EFI_NATIVE_INTERFACE
,
4202 &mPrivateData
.HiiPopup
4204 ASSERT_EFI_ERROR (Status
);
4206 InitializeDisplayStrings();
4208 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
4209 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
4212 // Use BrowserEx2 protocol to register HotKey.
4214 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
4215 if (!EFI_ERROR (Status
)) {
4217 // Register the default HotKey F9 and F10 again.
4219 HotKey
.UnicodeChar
= CHAR_NULL
;
4220 HotKey
.ScanCode
= SCAN_F10
;
4221 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
4222 ASSERT (NewString
!= NULL
);
4223 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
4225 HotKey
.ScanCode
= SCAN_F9
;
4226 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
4227 ASSERT (NewString
!= NULL
);
4228 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
4235 This is the default unload handle for display core drivers.
4237 @param[in] ImageHandle The drivers' driver image.
4239 @retval EFI_SUCCESS The image is unloaded.
4240 @retval Others Failed to unload the image.
4245 UnloadDisplayEngine (
4246 IN EFI_HANDLE ImageHandle
4249 HiiRemovePackages(gHiiHandle
);
4251 FreeDisplayStrings ();
4253 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
4254 FreePool (gHighligthMenuInfo
.HLTOpCode
);
4257 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
4258 FreePool (gHighligthMenuInfo
.TOSOpCode
);