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
*gConfirmMsgConnect
;
155 CHAR16
*gConfirmMsgEnd
;
156 CHAR16
*gPasswordUnsupported
;
157 CHAR16 gModalSkipColumn
;
158 CHAR16 gPromptBlockWidth
;
159 CHAR16 gOptionBlockWidth
;
160 CHAR16 gHelpBlockWidth
;
161 CHAR16
*mUnknownString
;
163 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
164 FORM_DISPLAY_DRIVER_SIGNATURE
,
168 DriverClearDisplayPage
,
175 Get the string based on the StringId and HII Package List Handle.
177 @param Token The String's ID.
178 @param HiiHandle The package list in the HII database to search for
179 the specified string.
181 @return The output string.
186 IN EFI_STRING_ID Token
,
187 IN EFI_HII_HANDLE HiiHandle
192 String
= HiiGetString (HiiHandle
, Token
, NULL
);
193 if (String
== NULL
) {
194 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
195 ASSERT (String
!= NULL
);
198 return (CHAR16
*) String
;
203 Initialize the HII String Token to the correct values.
207 InitializeDisplayStrings (
211 gReconnectConfirmChanges
= GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES
), gHiiHandle
);
212 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
213 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
214 gNoSubmitIfFailed
= GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED
), gHiiHandle
);
215 gReconnectFail
= GetToken (STRING_TOKEN (RECONNECT_FAILED
), gHiiHandle
);
216 gReconnectRequired
= GetToken (STRING_TOKEN (RECONNECT_REQUIRED
), gHiiHandle
);
217 gChangesOpt
= GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS
), gHiiHandle
);
218 gSaveProcess
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP
), gHiiHandle
);
219 gSaveNoSubmitProcess
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK
), gHiiHandle
);
220 gDiscardChange
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD
), gHiiHandle
);
221 gJumpToFormSet
= GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP
), gHiiHandle
);
222 gCheckError
= GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK
), gHiiHandle
);
223 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
224 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
225 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
226 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
227 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
228 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
229 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
230 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
231 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
232 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
233 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
234 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
235 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
236 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
237 gBrowserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
238 gConfirmDefaultMsg
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE
), gHiiHandle
);
239 gConfirmDiscardMsg
= GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE
), gHiiHandle
);
240 gConfirmSubmitMsg
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE
), gHiiHandle
);
241 gConfirmResetMsg
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE
), gHiiHandle
);
242 gConfirmExitMsg
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE
), gHiiHandle
);
243 gConfirmDefaultMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND
), gHiiHandle
);
244 gConfirmSubmitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND
), gHiiHandle
);
245 gConfirmResetMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND
), gHiiHandle
);
246 gConfirmExitMsg2nd
= GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND
), gHiiHandle
);
247 gConfirmOpt
= GetToken (STRING_TOKEN (CONFIRM_OPTION
), gHiiHandle
);
248 gConfirmOptYes
= GetToken (STRING_TOKEN (CONFIRM_OPTION_YES
), gHiiHandle
);
249 gConfirmOptNo
= GetToken (STRING_TOKEN (CONFIRM_OPTION_NO
), gHiiHandle
);
250 gConfirmMsgConnect
= GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT
), gHiiHandle
);
251 gConfirmMsgEnd
= GetToken (STRING_TOKEN (CONFIRM_OPTION_END
), gHiiHandle
);
252 gPasswordUnsupported
= GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED
), gHiiHandle
);
256 Free up the resource allocated for all strings required
265 FreePool (mUnknownString
);
266 FreePool (gEmptyString
);
267 FreePool (gSaveFailed
);
268 FreePool (gNoSubmitIfFailed
);
269 FreePool (gReconnectFail
);
270 FreePool (gReconnectRequired
);
271 FreePool (gChangesOpt
);
272 FreePool (gReconnectConfirmChanges
);
273 FreePool (gSaveProcess
);
274 FreePool (gSaveNoSubmitProcess
);
275 FreePool (gDiscardChange
);
276 FreePool (gJumpToFormSet
);
277 FreePool (gCheckError
);
278 FreePool (gPromptForData
);
279 FreePool (gPromptForPassword
);
280 FreePool (gPromptForNewPassword
);
281 FreePool (gConfirmPassword
);
282 FreePool (gConfirmError
);
283 FreePool (gPassowordInvalid
);
284 FreePool (gPressEnter
);
285 FreePool (gMiniString
);
286 FreePool (gOptionMismatch
);
287 FreePool (gFormSuppress
);
288 FreePool (gProtocolNotFound
);
289 FreePool (gBrowserError
);
290 FreePool (gNoSubmitIf
);
291 FreePool (gFormNotFound
);
292 FreePool (gConfirmDefaultMsg
);
293 FreePool (gConfirmSubmitMsg
);
294 FreePool (gConfirmDiscardMsg
);
295 FreePool (gConfirmResetMsg
);
296 FreePool (gConfirmExitMsg
);
297 FreePool (gConfirmDefaultMsg2nd
);
298 FreePool (gConfirmSubmitMsg2nd
);
299 FreePool (gConfirmResetMsg2nd
);
300 FreePool (gConfirmExitMsg2nd
);
301 FreePool (gConfirmOpt
);
302 FreePool (gConfirmOptYes
);
303 FreePool (gConfirmOptNo
);
304 FreePool (gConfirmMsgConnect
);
305 FreePool (gConfirmMsgEnd
);
306 FreePool (gPasswordUnsupported
);
310 Get prompt string id from the opcode data buffer.
312 @param OpCode The input opcode buffer.
314 @return The prompt string id.
319 IN EFI_IFR_OP_HEADER
*OpCode
322 EFI_IFR_STATEMENT_HEADER
*Header
;
324 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
328 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
330 return Header
->Prompt
;
334 Get the supported width for a particular op-code
336 @param MenuOption The menu option.
337 @param AdjustWidth The width which is saved for the space.
339 @return Returns the number of CHAR16 characters that is support.
344 IN UI_MENU_OPTION
*MenuOption
,
345 OUT UINT16
*AdjustWidth
350 EFI_IFR_TEXT
*TestOp
;
352 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
354 Statement
= MenuOption
->ThisTag
;
357 // For modal form, clean the entire row.
359 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
360 if (AdjustWidth
!= NULL
) {
361 *AdjustWidth
= LEFT_SKIPPED_COLUMNS
;
363 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gModalSkipColumn
+ LEFT_SKIPPED_COLUMNS
));
369 // See if the second text parameter is really NULL
371 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
372 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
373 if (TestOp
->TextTwo
!= 0) {
374 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
375 Size
= StrLen (String
);
380 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
381 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
382 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
383 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
384 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
386 // Allow a wide display if text op-code and no secondary text op-code
388 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
392 // Return the space width.
394 if (AdjustWidth
!= NULL
) {
398 // Keep consistent with current behavior.
400 ReturnWidth
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
402 if (AdjustWidth
!= NULL
) {
406 ReturnWidth
= (UINT16
) (gPromptBlockWidth
- 1);
410 // For nest in statement, should the subtitle indent.
412 if (MenuOption
->NestInStatement
) {
413 ReturnWidth
-= SUBTITLE_INDENT
;
420 Will copy LineWidth amount of a string in the OutputString buffer and return the
421 number of CHAR16 characters that were copied into the OutputString buffer.
422 The output string format is:
423 Glyph Info + String info + '\0'.
425 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
427 @param InputString String description for this option.
428 @param LineWidth Width of the desired string to extract in CHAR16
430 @param GlyphWidth The glyph width of the begin of the char in the string.
431 @param Index Where in InputString to start the copy process
432 @param OutputString Buffer to copy the string into
434 @return Returns the number of CHAR16 characters that were copied into the OutputString
435 buffer, include extra glyph info and '\0' info.
440 IN CHAR16
*InputString
,
442 IN OUT UINT16
*GlyphWidth
,
444 OUT CHAR16
**OutputString
449 UINT16 OriginalGlyphWidth
;
451 UINT16 LastSpaceOffset
;
452 UINT16 LastGlyphWidth
;
454 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
458 if (LineWidth
== 0 || *GlyphWidth
== 0) {
463 // Save original glyph width.
465 OriginalGlyphWidth
= *GlyphWidth
;
466 LastGlyphWidth
= OriginalGlyphWidth
;
471 // 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.
472 // To avoid displaying this empty line in screen, just skip the two CHARs here.
474 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
479 // Fast-forward the string and see if there is a carriage-return in the string
481 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
482 switch (InputString
[*Index
+ StrOffset
]) {
491 case CHAR_CARRIAGE_RETURN
:
498 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
501 // Record the last space info in this line. Will be used in rewind.
503 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
504 LastSpaceOffset
= StrOffset
;
505 LastGlyphWidth
= *GlyphWidth
;
516 // Rewind the string from the maximum size until we see a space to break the line
518 if (GlyphOffset
> LineWidth
) {
520 // Rewind the string to last space char in this line.
522 if (LastSpaceOffset
!= 0) {
523 StrOffset
= LastSpaceOffset
;
524 *GlyphWidth
= LastGlyphWidth
;
527 // Roll back to last char in the line width.
534 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
536 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
541 // Need extra glyph info and '\0' info, so +2.
543 *OutputString
= AllocateZeroPool ((StrOffset
+ 2) * sizeof(CHAR16
));
544 if (*OutputString
== NULL
) {
549 // Save the glyph info at the begin of the string, will used by Print function.
551 if (OriginalGlyphWidth
== 1) {
552 *(*OutputString
) = NARROW_CHAR
;
554 *(*OutputString
) = WIDE_CHAR
;
557 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
559 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
561 // Skip the space info at the begin of next line.
563 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
564 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
566 // Skip the /n or /n/r info.
568 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
569 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
571 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
573 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
575 // Skip the /r or /r/n info.
577 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
578 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
580 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
583 *Index
= (UINT16
) (*Index
+ StrOffset
);
587 // Include extra glyph info and '\0' info, so +2.
589 return StrOffset
+ 2;
593 Add one menu option by specified description and context.
595 @param Statement Statement of this Menu Option.
596 @param MenuItemCount The index for this Option in the Menu.
597 @param NestIn Whether this statement is nest in another statement.
602 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
603 IN UINT16
*MenuItemCount
,
607 UI_MENU_OPTION
*MenuOption
;
610 UINT16 NumberOfLines
;
614 CHAR16
*OutputString
;
615 EFI_STRING_ID PromptId
;
623 PromptId
= GetPrompt (Statement
->OpCode
);
624 ASSERT (PromptId
!= 0);
626 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
630 for (Index
= 0; Index
< Count
; Index
++) {
631 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
634 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
635 MenuOption
->Description
= GetToken (PromptId
, gFormData
->HiiHandle
);
636 MenuOption
->Handle
= gFormData
->HiiHandle
;
637 MenuOption
->ThisTag
= Statement
;
638 MenuOption
->NestInStatement
= NestIn
;
639 MenuOption
->EntryNumber
= *MenuItemCount
;
641 MenuOption
->Sequence
= Index
;
643 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
644 MenuOption
->GrayOut
= TRUE
;
646 MenuOption
->GrayOut
= FALSE
;
649 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
650 MenuOption
->GrayOut
= TRUE
;
654 // If the form or the question has the lock attribute, deal same as grayout.
656 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
657 MenuOption
->GrayOut
= TRUE
;
660 switch (Statement
->OpCode
->OpCode
) {
661 case EFI_IFR_ORDERED_LIST_OP
:
662 case EFI_IFR_ONE_OF_OP
:
663 case EFI_IFR_NUMERIC_OP
:
664 case EFI_IFR_TIME_OP
:
665 case EFI_IFR_DATE_OP
:
666 case EFI_IFR_CHECKBOX_OP
:
667 case EFI_IFR_PASSWORD_OP
:
668 case EFI_IFR_STRING_OP
:
670 // User could change the value of these items
672 MenuOption
->IsQuestion
= TRUE
;
674 case EFI_IFR_TEXT_OP
:
675 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
677 // Initializing GrayOut option as TRUE for Text setup options
678 // so that those options will be Gray in colour and un selectable.
680 MenuOption
->GrayOut
= TRUE
;
684 MenuOption
->IsQuestion
= FALSE
;
688 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
689 MenuOption
->ReadOnly
= TRUE
;
690 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
691 MenuOption
->GrayOut
= TRUE
;
696 (Statement
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
697 (Statement
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
698 Width
= GetWidth (MenuOption
, NULL
);
699 for (; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
701 // If there is more string to process print on the next row and increment the Skip value
703 if (StrLen (&MenuOption
->Description
[ArrayEntry
]) != 0) {
706 FreePool (OutputString
);
710 // Add three MenuOptions for Date/Time
711 // Data format : [01/02/2004] [11:22:33]
712 // Line number : 0 0 1 0 0 1
719 // Override LineNumber for the MenuOption in Date/Time sequence
721 MenuOption
->Skip
= 1;
723 MenuOption
->Skip
= NumberOfLines
;
726 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
733 Create the menu list base on the form data info.
737 ConvertStatementToMenu (
741 UINT16 MenuItemCount
;
743 LIST_ENTRY
*NestLink
;
744 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
745 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
748 InitializeListHead (&gMenuOption
);
750 Link
= GetFirstNode (&gFormData
->StatementListHead
);
751 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
752 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
753 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
756 // Skip the opcode not recognized by Display core.
758 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
762 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
765 // Check the statement nest in this host statement.
767 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
768 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
769 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
770 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
773 // Skip the opcode not recognized by Display core.
775 if (NestStatement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
779 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
785 Count the storage space of a Unicode string.
787 This function handles the Unicode string with NARROW_CHAR
788 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
789 does not count in the resultant output. If a WIDE_CHAR is
790 hit, then 2 Unicode character will consume an output storage
791 space with size of CHAR16 till a NARROW_CHAR is hit.
793 If String is NULL, then ASSERT ().
795 @param String The input string to be counted.
797 @return Storage space for the input string.
807 UINTN IncrementValue
;
809 ASSERT (String
!= NULL
);
810 if (String
== NULL
) {
820 // Advance to the null-terminator or to the first width directive
823 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
824 Index
++, Count
= Count
+ IncrementValue
829 // We hit the null-terminator, we now have a count
831 if (String
[Index
] == 0) {
835 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
836 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
838 if (String
[Index
] == NARROW_CHAR
) {
840 // Skip to the next character
846 // Skip to the next character
851 } while (String
[Index
] != 0);
854 // Increment by one to include the null-terminator in the size
858 return Count
* sizeof (CHAR16
);
862 Base on the input option string to update the skip value for a menu option.
864 @param MenuOption The MenuOption to be checked.
865 @param OptionString The input option string.
869 UpdateSkipInfoForMenu (
870 IN UI_MENU_OPTION
*MenuOption
,
871 IN CHAR16
*OptionString
877 CHAR16
*OutputString
;
880 Width
= (UINT16
) gOptionBlockWidth
- 1;
884 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
885 if (StrLen (&OptionString
[Index
]) != 0) {
889 FreePool (OutputString
);
892 if ((Row
> MenuOption
->Skip
) &&
893 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
894 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
895 MenuOption
->Skip
= Row
;
900 Update display lines for a Menu Option.
902 @param MenuOption The MenuOption to be checked.
906 UpdateOptionSkipLines (
907 IN UI_MENU_OPTION
*MenuOption
910 CHAR16
*OptionString
;
914 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
915 if (OptionString
!= NULL
) {
916 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
918 FreePool (OptionString
);
921 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
922 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
924 if (OptionString
!= NULL
) {
925 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
927 FreePool (OptionString
);
933 Check whether this Menu Option could be print.
935 Check Prompt string, option string or text two string not NULL.
937 This is an internal function.
939 @param MenuOption The MenuOption to be checked.
941 @retval TRUE This Menu Option is printable.
942 @retval FALSE This Menu Option could not be printable.
947 UI_MENU_OPTION
*MenuOption
951 EFI_STRING OptionString
;
955 if (MenuOption
->Description
[0] != '\0') {
959 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
960 if (EFI_ERROR (Status
)) {
963 if (OptionString
!= NULL
&& OptionString
[0] != '\0') {
964 FreePool (OptionString
);
968 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
969 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
970 ASSERT (OptionString
!= NULL
);
971 if (OptionString
[0] != '\0'){
972 FreePool (OptionString
);
981 Check whether this Menu Option could be highlighted.
983 This is an internal function.
985 @param MenuOption The MenuOption to be checked.
987 @retval TRUE This Menu Option is selectable.
988 @retval FALSE This Menu Option could not be selected.
993 UI_MENU_OPTION
*MenuOption
996 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
997 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
|| !PrintableMenu (MenuOption
)) {
1005 Move to next selectable statement.
1007 This is an internal function.
1009 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1010 @param CurrentPosition Current position.
1011 @param GapToTop Gap position to top or bottom.
1012 @param FindInForm Whether find menu in current form or beyond.
1014 @return The row distance from current MenuOption to next selectable MenuOption.
1016 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
1017 @retval Value Find the selectable menu, maybe the truly selectable, maybe the
1018 first menu showing beyond current form or last menu showing in
1020 The value is the line number between the new selected menu and the
1021 current select menu, not include the new selected menu.
1025 MoveToNextStatement (
1027 IN OUT LIST_ENTRY
**CurrentPosition
,
1029 IN BOOLEAN FindInForm
1034 UI_MENU_OPTION
*NextMenuOption
;
1035 UI_MENU_OPTION
*PreMenuOption
;
1038 Pos
= *CurrentPosition
;
1040 if (Pos
== &gMenuOption
) {
1044 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1047 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1049 // NextMenuOption->Row == 0 means this menu has not calculate
1050 // the NextMenuOption->Skip value yet, just calculate here.
1052 if (NextMenuOption
->Row
== 0) {
1053 UpdateOptionSkipLines (NextMenuOption
);
1057 // Check whether the menu is beyond current showing form,
1058 // return the first one beyond the showing form.
1060 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1062 NextMenuOption
= PreMenuOption
;
1068 // return the selectable menu in the showing form.
1070 if (IsSelectable (NextMenuOption
)) {
1074 Distance
+= NextMenuOption
->Skip
;
1077 // Arrive at begin of the menu list.
1079 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1084 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1085 PreMenuOption
= NextMenuOption
;
1088 *CurrentPosition
= &NextMenuOption
->Link
;
1094 Process option string for date/time opcode.
1096 @param MenuOption Menu option point to date/time.
1097 @param OptionString Option string input for process.
1098 @param AddOptCol Whether need to update MenuOption->OptCol.
1102 ProcessStringForDateTime (
1103 UI_MENU_OPTION
*MenuOption
,
1104 CHAR16
*OptionString
,
1110 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1114 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
1116 Statement
= MenuOption
->ThisTag
;
1119 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1120 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
1121 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1122 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
1126 // If leading spaces on OptionString - remove the spaces
1128 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1130 // Base on the blockspace to get the option column info.
1133 MenuOption
->OptCol
++;
1137 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1138 OptionString
[Count
] = OptionString
[Index
];
1141 OptionString
[Count
] = CHAR_NULL
;
1144 // Enable to suppress field in the opcode base on the flag.
1146 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1148 // OptionString format is: <**: **: ****>
1152 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1154 // At this point, only "<**:" in the optionstring.
1155 // Clean the day's ** field, after clean, the format is "< :"
1157 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1158 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1160 // At this point, only "**:" in the optionstring.
1161 // Clean the month's "**" field, after clean, the format is " :"
1163 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1164 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1166 // At this point, only "****>" in the optionstring.
1167 // Clean the year's "****" field, after clean, the format is " >"
1169 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1171 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1173 // OptionString format is: <**: **: **>
1174 // |hour|minute|second|
1177 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1179 // At this point, only "<**:" in the optionstring.
1180 // Clean the hour's ** field, after clean, the format is "< :"
1182 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1183 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1185 // At this point, only "**:" in the optionstring.
1186 // Clean the minute's "**" field, after clean, the format is " :"
1188 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1189 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1191 // At this point, only "**>" in the optionstring.
1192 // Clean the second's "**" field, after clean, the format is " >"
1194 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1201 Adjust Data and Time position accordingly.
1202 Data format : [01/02/2004] [11:22:33]
1203 Line number : 0 0 1 0 0 1
1205 This is an internal function.
1207 @param DirectionUp the up or down direction. False is down. True is
1209 @param CurrentPosition Current position. On return: Point to the last
1210 Option (Year or Second) if up; Point to the first
1211 Option (Month or Hour) if down.
1213 @return Return line number to pad. It is possible that we stand on a zero-advance
1214 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1218 AdjustDateAndTimePosition (
1219 IN BOOLEAN DirectionUp
,
1220 IN OUT LIST_ENTRY
**CurrentPosition
1224 LIST_ENTRY
*NewPosition
;
1225 UI_MENU_OPTION
*MenuOption
;
1226 UINTN PadLineNumber
;
1229 NewPosition
= *CurrentPosition
;
1230 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1232 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1233 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1235 // Calculate the distance from current position to the last Date/Time MenuOption
1238 while (MenuOption
->Skip
== 0) {
1240 NewPosition
= NewPosition
->ForwardLink
;
1241 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1245 NewPosition
= *CurrentPosition
;
1248 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1249 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1250 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1251 // checking can be done.
1253 while (Count
++ < 2) {
1254 NewPosition
= NewPosition
->BackLink
;
1258 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1259 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1260 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1261 // checking can be done.
1263 while (Count
-- > 0) {
1264 NewPosition
= NewPosition
->ForwardLink
;
1268 *CurrentPosition
= NewPosition
;
1271 return PadLineNumber
;
1275 Get step info from numeric opcode.
1277 @param[in] OpCode The input numeric op code.
1279 @return step info for this opcode.
1283 IN EFI_IFR_OP_HEADER
*OpCode
1286 EFI_IFR_NUMERIC
*NumericOp
;
1289 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1291 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1292 case EFI_IFR_NUMERIC_SIZE_1
:
1293 Step
= NumericOp
->data
.u8
.Step
;
1296 case EFI_IFR_NUMERIC_SIZE_2
:
1297 Step
= NumericOp
->data
.u16
.Step
;
1300 case EFI_IFR_NUMERIC_SIZE_4
:
1301 Step
= NumericOp
->data
.u32
.Step
;
1304 case EFI_IFR_NUMERIC_SIZE_8
:
1305 Step
= NumericOp
->data
.u64
.Step
;
1317 Find the registered HotKey based on KeyData.
1319 @param[in] KeyData A pointer to a buffer that describes the keystroke
1320 information for the hot key.
1322 @return The registered HotKey context. If no found, NULL will return.
1325 GetHotKeyFromRegisterList (
1326 IN EFI_INPUT_KEY
*KeyData
1330 BROWSER_HOT_KEY
*HotKey
;
1332 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1333 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1334 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1336 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1340 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1348 Determine if the menu is the last menu that can be selected.
1350 This is an internal function.
1352 @param Direction The scroll direction. False is down. True is up.
1353 @param CurrentPos The current focus.
1355 @return FALSE -- the menu isn't the last menu that can be selected.
1356 @return TRUE -- the menu is the last menu that can be selected.
1361 IN BOOLEAN Direction
,
1362 IN LIST_ENTRY
*CurrentPos
1367 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1369 if (Temp
== &gMenuOption
) {
1377 Wait for a given event to fire, or for an optional timeout to expire.
1379 @param Event The event to wait for
1381 @retval UI_EVENT_TYPE The type of the event which is trigged.
1393 EFI_EVENT TimerEvent
;
1394 EFI_EVENT WaitList
[3];
1395 UI_EVENT_TYPE EventType
;
1398 Timeout
= FormExitTimeout(gFormData
);
1401 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1404 // Set the timer event
1413 WaitList
[0] = Event
;
1415 if (gFormData
->FormRefreshEvent
!= NULL
) {
1416 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1421 WaitList
[EventNum
] = TimerEvent
;
1425 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1426 ASSERT_EFI_ERROR (Status
);
1430 EventType
= UIEventKey
;
1434 if (gFormData
->FormRefreshEvent
!= NULL
) {
1435 EventType
= UIEventDriver
;
1437 ASSERT (Timeout
!= 0 && EventNum
== 2);
1438 EventType
= UIEventTimeOut
;
1443 ASSERT (Index
== 2 && EventNum
== 3);
1444 EventType
= UIEventTimeOut
;
1449 gBS
->CloseEvent (TimerEvent
);
1456 Get question id info from the input opcode header.
1458 @param OpCode The input opcode header pointer.
1460 @retval The question id for this opcode.
1465 IN EFI_IFR_OP_HEADER
*OpCode
1468 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1470 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1474 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1476 return QuestionHeader
->QuestionId
;
1481 Find the top of screen menu base on the current menu.
1483 @param CurPos Current input menu.
1484 @param Rows Totol screen rows.
1485 @param SkipValue SkipValue for this new form.
1487 @retval TopOfScreen Top of screen menu for the new form.
1491 FindTopOfScreenMenu (
1492 IN LIST_ENTRY
*CurPos
,
1494 OUT UINTN
*SkipValue
1498 LIST_ENTRY
*TopOfScreen
;
1499 UI_MENU_OPTION
*PreviousMenuOption
;
1502 PreviousMenuOption
= NULL
;
1504 while (Link
->BackLink
!= &gMenuOption
) {
1505 Link
= Link
->BackLink
;
1506 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1507 if (PreviousMenuOption
->Row
== 0) {
1508 UpdateOptionSkipLines (PreviousMenuOption
);
1510 if (Rows
<= PreviousMenuOption
->Skip
) {
1513 Rows
= Rows
- PreviousMenuOption
->Skip
;
1516 if (Link
->BackLink
== &gMenuOption
) {
1517 TopOfScreen
= gMenuOption
.ForwardLink
;
1518 if (PreviousMenuOption
!= NULL
&& Rows
< PreviousMenuOption
->Skip
) {
1519 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1525 *SkipValue
= PreviousMenuOption
->Skip
- Rows
;
1532 Get the index info for this opcode.
1534 @param OpCode The input opcode for the statement.
1536 @retval The index of this statement.
1540 GetIndexInfoForOpcode (
1541 IN EFI_IFR_OP_HEADER
*OpCode
1545 UI_MENU_OPTION
*MenuOption
;
1548 NewPos
= gMenuOption
.ForwardLink
;
1551 for (NewPos
= gMenuOption
.ForwardLink
; NewPos
!= &gMenuOption
; NewPos
= NewPos
->ForwardLink
){
1552 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1554 if (CompareMem (MenuOption
->ThisTag
->OpCode
, OpCode
, OpCode
->Length
) == 0) {
1555 if (MenuOption
->ThisTag
->OpCode
== OpCode
) {
1567 Is this the saved highlight statement.
1569 @param HighLightedStatement The input highlight statement.
1571 @retval TRUE This is the highlight statement.
1572 @retval FALSE This is not the highlight statement.
1576 IsSavedHighlightStatement (
1577 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1580 if ((gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
) &&
1581 (gFormData
->FormId
== gHighligthMenuInfo
.FormId
)) {
1582 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1583 return (BOOLEAN
) (gHighligthMenuInfo
.HLTQuestionId
== GetQuestionIdInfo (HighLightedStatement
->OpCode
));
1585 if (CompareMem (gHighligthMenuInfo
.HLTOpCode
, HighLightedStatement
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1586 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(HighLightedStatement
->OpCode
)) {
1599 Is this the highlight menu.
1601 @param MenuOption The input Menu option.
1603 @retval TRUE This is the highlight menu option.
1604 @retval FALSE This is not the highlight menu option.
1608 IsHighLightMenuOption (
1609 IN UI_MENU_OPTION
*MenuOption
1612 if (gHighligthMenuInfo
.HLTQuestionId
!= 0) {
1613 if (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.HLTQuestionId
) {
1614 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1617 if(CompareMem (gHighligthMenuInfo
.HLTOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.HLTOpCode
->Length
) == 0) {
1618 if (gHighligthMenuInfo
.HLTIndex
== 0 || gHighligthMenuInfo
.HLTIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1619 return (BOOLEAN
) (MenuOption
->Sequence
== gHighligthMenuInfo
.HLTSequence
);
1630 Find the highlight menu.
1632 If the input is NULL, base on the record highlight info in
1633 gHighligthMenuInfo to find the last highlight menu.
1635 @param HighLightedStatement The input highlight statement.
1637 @retval The highlight menu index.
1641 FindHighLightMenuOption (
1642 IN FORM_DISPLAY_ENGINE_STATEMENT
*HighLightedStatement
1646 UI_MENU_OPTION
*MenuOption
;
1648 NewPos
= gMenuOption
.ForwardLink
;
1649 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1651 if (HighLightedStatement
!= NULL
) {
1652 while (MenuOption
->ThisTag
!= HighLightedStatement
) {
1653 NewPos
= NewPos
->ForwardLink
;
1654 if (NewPos
== &gMenuOption
) {
1656 // Not Found it, break
1660 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1664 // Must find the highlight statement.
1666 ASSERT (NewPos
!= &gMenuOption
);
1669 while (!IsHighLightMenuOption (MenuOption
)) {
1670 NewPos
= NewPos
->ForwardLink
;
1671 if (NewPos
== &gMenuOption
) {
1673 // Not Found it, break
1677 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1681 // Highlight statement has disappear (suppressed/disableed)
1683 if (NewPos
== &gMenuOption
) {
1692 Is this the Top of screen menu.
1694 @param MenuOption The input Menu option.
1696 @retval TRUE This is the Top of screen menu option.
1697 @retval FALSE This is not the Top of screen menu option.
1701 IsTopOfScreeMenuOption (
1702 IN UI_MENU_OPTION
*MenuOption
1705 if (gHighligthMenuInfo
.TOSQuestionId
!= 0) {
1706 return (BOOLEAN
) (GetQuestionIdInfo(MenuOption
->ThisTag
->OpCode
) == gHighligthMenuInfo
.TOSQuestionId
);
1709 if(CompareMem (gHighligthMenuInfo
.TOSOpCode
, MenuOption
->ThisTag
->OpCode
, gHighligthMenuInfo
.TOSOpCode
->Length
) == 0) {
1710 if (gHighligthMenuInfo
.TOSIndex
== 0 || gHighligthMenuInfo
.TOSIndex
== GetIndexInfoForOpcode(MenuOption
->ThisTag
->OpCode
)) {
1721 Calculate the distance between two menus and include the skip value of StartMenu.
1723 @param StartMenu The link_entry pointer to start menu.
1724 @param EndMenu The link_entry pointer to end menu.
1728 GetDistanceBetweenMenus(
1729 IN LIST_ENTRY
*StartMenu
,
1730 IN LIST_ENTRY
*EndMenu
1734 UI_MENU_OPTION
*MenuOption
;
1740 while (Link
!= EndMenu
) {
1741 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1742 if (MenuOption
->Row
== 0) {
1743 UpdateOptionSkipLines (MenuOption
);
1745 Distance
+= MenuOption
->Skip
;
1746 Link
= Link
->BackLink
;
1752 Find the top of screen menu base on the previous record menu info.
1754 @param HighLightMenu The link_entry pointer to highlight menu.
1756 @retval Return the the link_entry pointer top of screen menu.
1760 FindTopOfScreenMenuOption (
1761 IN LIST_ENTRY
*HighLightMenu
1765 UI_MENU_OPTION
*MenuOption
;
1769 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1770 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1772 NewPos
= gMenuOption
.ForwardLink
;
1773 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1775 while (!IsTopOfScreeMenuOption(MenuOption
)) {
1776 NewPos
= NewPos
->ForwardLink
;
1777 if (NewPos
== &gMenuOption
) {
1779 // Not Found it, break
1783 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1787 // Last time top of screen menu has disappeared.
1789 if (NewPos
== &gMenuOption
) {
1793 // Check whether highlight menu and top of screen menu can be shown within one page,
1794 // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
1795 // may be dynamically inserted between highlightmenu and previous top of screen menu,
1796 // So previous record top of screen menu is not appropriate for current display.
1798 if (GetDistanceBetweenMenus (HighLightMenu
, NewPos
) + 1 > BottomRow
- TopRow
) {
1806 Find the first menu which will be show at the top.
1808 @param FormData The data info for this form.
1809 @param TopOfScreen The link_entry pointer to top menu.
1810 @param HighlightMenu The menu which will be highlight.
1811 @param SkipValue The skip value for the top menu.
1816 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1817 OUT LIST_ENTRY
**TopOfScreen
,
1818 OUT LIST_ENTRY
**HighlightMenu
,
1819 OUT UINTN
*SkipValue
1824 UI_MENU_OPTION
*MenuOption
;
1827 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1828 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1830 // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
1831 // and the other is exit current form and enter last form, it can be covered by the else case.
1833 if (gMisMatch
&& gFormData
->HiiHandle
== gHighligthMenuInfo
.HiiHandle
&& gFormData
->FormId
== gHighligthMenuInfo
.FormId
) {
1835 // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
1836 // base on the record highlight info to find the highlight menu.
1839 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1840 if (*HighlightMenu
!= NULL
) {
1842 // Update skip info for this highlight menu.
1844 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1845 UpdateOptionSkipLines (MenuOption
);
1848 // Found the last time highlight menu.
1850 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1851 if (*TopOfScreen
!= NULL
) {
1853 // Found the last time selectable top of screen menu.
1855 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1856 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1857 UpdateOptionSkipLines (MenuOption
);
1859 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1862 // Not found last time top of screen menu, so base on current highlight menu
1863 // to find the new top of screen menu.
1864 // Make the current highlight menu at the bottom of the form to calculate the
1865 // top of screen menu.
1867 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1868 *TopOfScreen
= *HighlightMenu
;
1871 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1874 *SkipValue
= TmpValue
;
1878 // Last time highlight menu has disappear, find the first highlightable menu as the default one.
1880 *HighlightMenu
= gMenuOption
.ForwardLink
;
1881 if (!IsListEmpty (&gMenuOption
)) {
1882 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1884 *TopOfScreen
= gMenuOption
.ForwardLink
;
1888 } else if (FormData
->HighLightedStatement
!= NULL
) {
1889 if (IsSavedHighlightStatement (FormData
->HighLightedStatement
)) {
1891 // Input highlight menu is same as last time highlight menu.
1892 // Base on last time highlight menu to set the top of screen menu and highlight menu.
1894 *HighlightMenu
= FindHighLightMenuOption(NULL
);
1895 ASSERT (*HighlightMenu
!= NULL
);
1898 // Update skip info for this highlight menu.
1900 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1901 UpdateOptionSkipLines (MenuOption
);
1903 *TopOfScreen
= FindTopOfScreenMenuOption(*HighlightMenu
);
1904 if (*TopOfScreen
== NULL
) {
1906 // Not found last time top of screen menu, so base on current highlight menu
1907 // to find the new top of screen menu.
1908 // Make the current highlight menu at the bottom of the form to calculate the
1909 // top of screen menu.
1911 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1912 *TopOfScreen
= *HighlightMenu
;
1915 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1918 *SkipValue
= TmpValue
;
1920 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1921 MenuOption
= MENU_OPTION_FROM_LINK (*TopOfScreen
);
1922 UpdateOptionSkipLines (MenuOption
);
1924 *SkipValue
= gHighligthMenuInfo
.SkipValue
;
1926 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1929 // Input highlight menu is not save as last time highlight menu.
1931 *HighlightMenu
= FindHighLightMenuOption(FormData
->HighLightedStatement
);
1932 MenuOption
= MENU_OPTION_FROM_LINK (*HighlightMenu
);
1933 UpdateOptionSkipLines (MenuOption
);
1936 // Make the current highlight menu at the bottom of the form to calculate the
1937 // top of screen menu.
1939 if (MenuOption
->Skip
>= BottomRow
- TopRow
) {
1940 *TopOfScreen
= *HighlightMenu
;
1943 *TopOfScreen
= FindTopOfScreenMenu(*HighlightMenu
, BottomRow
- TopRow
- MenuOption
->Skip
, &TmpValue
);
1946 *SkipValue
= TmpValue
;
1948 AdjustDateAndTimePosition(TRUE
, TopOfScreen
);
1951 // If not has input highlight statement, just return the first one in this form.
1953 *TopOfScreen
= gMenuOption
.ForwardLink
;
1954 *HighlightMenu
= gMenuOption
.ForwardLink
;
1955 if (!IsListEmpty (&gMenuOption
)) {
1956 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
, TRUE
);
1964 // First enter to show the menu, update highlight info.
1966 UpdateHighlightMenuInfo (*HighlightMenu
, *TopOfScreen
, *SkipValue
);
1970 Record the highlight menu and top of screen menu info.
1972 @param Highlight The menu opton which is highlight.
1973 @param TopOfScreen The menu opton which is at the top of the form.
1974 @param SkipValue The skip line info for the top of screen menu.
1978 UpdateHighlightMenuInfo (
1979 IN LIST_ENTRY
*Highlight
,
1980 IN LIST_ENTRY
*TopOfScreen
,
1984 UI_MENU_OPTION
*MenuOption
;
1985 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1987 gHighligthMenuInfo
.HiiHandle
= gFormData
->HiiHandle
;
1988 gHighligthMenuInfo
.FormId
= gFormData
->FormId
;
1989 gHighligthMenuInfo
.SkipValue
= (UINT16
)SkipValue
;
1991 if (!IsListEmpty (&gMenuOption
)) {
1992 MenuOption
= MENU_OPTION_FROM_LINK (Highlight
);
1993 Statement
= MenuOption
->ThisTag
;
1995 gUserInput
->SelectedStatement
= Statement
;
1997 gHighligthMenuInfo
.HLTSequence
= MenuOption
->Sequence
;
1998 gHighligthMenuInfo
.HLTQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1999 if (gHighligthMenuInfo
.HLTQuestionId
== 0) {
2001 // if question id == 0, save the opcode buffer..
2003 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2004 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2006 gHighligthMenuInfo
.HLTOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2007 ASSERT (gHighligthMenuInfo
.HLTOpCode
!= NULL
);
2009 gHighligthMenuInfo
.HLTIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2012 MenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2013 Statement
= MenuOption
->ThisTag
;
2015 gHighligthMenuInfo
.TOSQuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
2016 if (gHighligthMenuInfo
.TOSQuestionId
== 0) {
2018 // if question id == 0, save the opcode buffer..
2020 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2021 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2023 gHighligthMenuInfo
.TOSOpCode
= AllocateCopyPool (Statement
->OpCode
->Length
, Statement
->OpCode
);
2024 ASSERT (gHighligthMenuInfo
.TOSOpCode
!= NULL
);
2026 gHighligthMenuInfo
.TOSIndex
= GetIndexInfoForOpcode(Statement
->OpCode
);
2029 gUserInput
->SelectedStatement
= NULL
;
2031 gHighligthMenuInfo
.HLTSequence
= 0;
2032 gHighligthMenuInfo
.HLTQuestionId
= 0;
2033 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
2034 FreePool (gHighligthMenuInfo
.HLTOpCode
);
2036 gHighligthMenuInfo
.HLTOpCode
= NULL
;
2037 gHighligthMenuInfo
.HLTIndex
= 0;
2039 gHighligthMenuInfo
.TOSQuestionId
= 0;
2040 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
2041 FreePool (gHighligthMenuInfo
.TOSOpCode
);
2043 gHighligthMenuInfo
.TOSOpCode
= NULL
;
2044 gHighligthMenuInfo
.TOSIndex
= 0;
2049 Update attribut for this menu.
2051 @param MenuOption The menu opton which this attribut used to.
2052 @param Highlight Whether this menu will be highlight.
2056 SetDisplayAttribute (
2057 IN UI_MENU_OPTION
*MenuOption
,
2058 IN BOOLEAN Highlight
2061 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2063 Statement
= MenuOption
->ThisTag
;
2066 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2070 if (MenuOption
->GrayOut
) {
2071 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2073 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2074 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2076 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2082 Print string for this menu option.
2084 @param MenuOption The menu opton which this attribut used to.
2085 @param Col The column that this string will be print at.
2086 @param Row The row that this string will be print at.
2087 @param String The string which need to print.
2088 @param Width The width need to print, if string is less than the
2089 width, the block space will be used.
2090 @param Highlight Whether this menu will be highlight.
2095 IN UI_MENU_OPTION
*MenuOption
,
2100 IN BOOLEAN Highlight
2106 // Print string with normal color.
2109 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
2114 // Print the highlight menu string.
2115 // First print the highlight string.
2117 SetDisplayAttribute(MenuOption
, TRUE
);
2118 Length
= PrintStringAt (Col
, Row
, String
);
2121 // Second, clean the empty after the string.
2123 SetDisplayAttribute(MenuOption
, FALSE
);
2124 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
2128 Check whether this menu can has option string.
2130 @param MenuOption The menu opton which this attribut used to.
2132 @retval TRUE This menu option can have option string.
2133 @retval FALSE This menu option can't have option string.
2138 IN UI_MENU_OPTION
*MenuOption
2141 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2144 EFI_IFR_TEXT
*TestOp
;
2147 Statement
= MenuOption
->ThisTag
;
2150 // See if the second text parameter is really NULL
2152 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2153 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
2154 if (TestOp
->TextTwo
!= 0) {
2155 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
2156 Size
= StrLen (String
);
2161 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
2162 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
2163 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
2164 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
2165 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
2167 // Allow a wide display if text op-code and no secondary text op-code
2169 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
2179 Double confirm with user about the action.
2181 @param Action The user input action.
2183 @retval TRUE User confirm with the input or not need user confirm.
2184 @retval FALSE User want ignore this input.
2201 CatLen
= StrLen (gConfirmMsgConnect
);
2204 // Below action need extra popup dialog to confirm.
2206 CheckFlags
= BROWSER_ACTION_DISCARD
|
2207 BROWSER_ACTION_DEFAULT
|
2208 BROWSER_ACTION_SUBMIT
|
2209 BROWSER_ACTION_RESET
|
2210 BROWSER_ACTION_EXIT
;
2213 // Not need to confirm with user, just return TRUE.
2215 if ((Action
& CheckFlags
) == 0) {
2219 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2220 CfmStrLen
+= StrLen (gConfirmDiscardMsg
);
2223 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2224 if (CfmStrLen
!= 0) {
2225 CfmStrLen
+= CatLen
;
2228 CfmStrLen
+= StrLen (gConfirmDefaultMsg
);
2231 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2232 if (CfmStrLen
!= 0) {
2233 CfmStrLen
+= CatLen
;
2236 CfmStrLen
+= StrLen (gConfirmSubmitMsg
);
2239 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2240 if (CfmStrLen
!= 0) {
2241 CfmStrLen
+= CatLen
;
2244 CfmStrLen
+= StrLen (gConfirmResetMsg
);
2247 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2248 if (CfmStrLen
!= 0) {
2249 CfmStrLen
+= CatLen
;
2252 CfmStrLen
+= StrLen (gConfirmExitMsg
);
2256 // Allocate buffer to save the string.
2257 // String + "?" + "\0"
2259 MaxLen
= CfmStrLen
+ 1 + 1;
2260 CfmStr
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
2261 ASSERT (CfmStr
!= NULL
);
2263 if ((Action
& BROWSER_ACTION_DISCARD
) == BROWSER_ACTION_DISCARD
) {
2264 StrCpyS (CfmStr
, MaxLen
, gConfirmDiscardMsg
);
2267 if ((Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
2268 if (CfmStr
[0] != 0) {
2269 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2270 StrCatS (CfmStr
, MaxLen
, gConfirmDefaultMsg2nd
);
2272 StrCpyS (CfmStr
, MaxLen
, gConfirmDefaultMsg
);
2276 if ((Action
& BROWSER_ACTION_SUBMIT
) == BROWSER_ACTION_SUBMIT
) {
2277 if (CfmStr
[0] != 0) {
2278 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2279 StrCatS (CfmStr
, MaxLen
, gConfirmSubmitMsg2nd
);
2281 StrCpyS (CfmStr
, MaxLen
, gConfirmSubmitMsg
);
2285 if ((Action
& BROWSER_ACTION_RESET
) == BROWSER_ACTION_RESET
) {
2286 if (CfmStr
[0] != 0) {
2287 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2288 StrCatS (CfmStr
, MaxLen
, gConfirmResetMsg2nd
);
2290 StrCpyS (CfmStr
, MaxLen
, gConfirmResetMsg
);
2294 if ((Action
& BROWSER_ACTION_EXIT
) == BROWSER_ACTION_EXIT
) {
2295 if (CfmStr
[0] != 0) {
2296 StrCatS (CfmStr
, MaxLen
, gConfirmMsgConnect
);
2297 StrCatS (CfmStr
, MaxLen
, gConfirmExitMsg2nd
);
2299 StrCpyS (CfmStr
, MaxLen
, gConfirmExitMsg
);
2303 StrCatS (CfmStr
, MaxLen
, gConfirmMsgEnd
);
2306 CreateDialog (&Key
, gEmptyString
, CfmStr
, gConfirmOpt
, gEmptyString
, NULL
);
2307 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2308 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (gConfirmOptNo
[0] | UPPER_LOWER_CASE_OFFSET
)) &&
2309 (Key
.ScanCode
!= SCAN_ESC
));
2311 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (gConfirmOptYes
[0] | UPPER_LOWER_CASE_OFFSET
)) {
2323 Print string for this menu option.
2325 @param MenuOption The menu opton which this attribut used to.
2326 @param SkipWidth The skip width between the left to the start of the prompt.
2327 @param BeginCol The begin column for one menu.
2328 @param SkipLine The skip line for this menu.
2329 @param BottomRow The bottom row for this form.
2330 @param Highlight Whether this menu will be highlight.
2331 @param UpdateCol Whether need to update the column info for Date/Time.
2333 @retval EFI_SUCESSS Process the user selection success.
2338 IN UI_MENU_OPTION
*MenuOption
,
2343 IN BOOLEAN Highlight
,
2344 IN BOOLEAN UpdateCol
2347 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2352 CHAR16
*OptionString
;
2353 CHAR16
*OutputString
;
2360 BOOLEAN IsProcessingFirstRow
;
2362 UINTN PromptLineNum
;
2363 UINTN OptionLineNum
;
2367 Statement
= MenuOption
->ThisTag
;
2375 IsProcessingFirstRow
= TRUE
;
2378 // Set default color.
2380 SetDisplayAttribute (MenuOption
, FALSE
);
2383 // 1. Paint the option string.
2385 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
2386 if (EFI_ERROR (Status
)) {
2390 if (OptionString
!= NULL
) {
2391 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2393 // Adjust option string for date/time opcode.
2395 ProcessStringForDateTime(MenuOption
, OptionString
, UpdateCol
);
2398 Width
= (UINT16
) gOptionBlockWidth
- 1;
2399 Row
= MenuOption
->Row
;
2403 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2404 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
2405 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2407 // For date/time question, it has three menu options for this qustion.
2408 // The first/second menu options with the skip value is 0. the last one
2409 // with skip value is 1.
2411 if (MenuOption
->Skip
!= 0) {
2413 // For date/ time, print the last past (year for date and second for time)
2414 // - 7 means skip [##/##/ for date and [##:##: for time.
2416 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
2419 // For date/ time, print the first and second past (year for date and second for time)
2420 // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
2421 // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
2422 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
) - 1, Highlight
);
2425 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2431 // If there is more string to process print on the next row and increment the Skip value
2433 if (StrLen (&OptionString
[Index
]) != 0) {
2437 // Since the Number of lines for this menu entry may or may not be reflected accurately
2438 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2439 // some testing to ensure we are keeping this in-sync.
2441 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2443 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2449 FreePool (OutputString
);
2457 FreePool (OptionString
);
2461 // 2. Paint the description.
2463 PromptWidth
= GetWidth (MenuOption
, &AdjustValue
);
2464 Row
= MenuOption
->Row
;
2468 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
2469 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
2472 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2473 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2475 // 1.Clean the start LEFT_SKIPPED_COLUMNS
2477 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
2479 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2 && IsProcessingFirstRow
) {
2481 // Print Arrow for Goto button.
2484 MenuOption
->Col
- 2,
2486 GEOMETRICSHAPE_RIGHT_TRIANGLE
2488 IsProcessingFirstRow
= FALSE
;
2490 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
2494 // If there is more string to process print on the next row and increment the Skip value
2496 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2502 FreePool (OutputString
);
2513 // 3. If this is a text op with secondary text information
2515 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
2516 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
2518 Width
= (UINT16
) gOptionBlockWidth
- 1;
2519 Row
= MenuOption
->Row
;
2523 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2524 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
2525 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
2529 // If there is more string to process print on the next row and increment the Skip value
2531 if (StrLen (&StringPtr
[Index
]) != 0) {
2535 // If the rows for text two is greater than or equal to the skip value, increase the skip value
2537 if ((Row
- MenuOption
->Row
) >= MenuOption
->Skip
) {
2543 FreePool (OutputString
);
2549 FreePool (StringPtr
);
2553 // 4.Line number for Option string and prompt string are not equal.
2554 // Clean the column whose line number is less.
2556 if (HasOptionString(MenuOption
) && (OptionLineNum
!= PromptLineNum
)) {
2557 Col
= OptionLineNum
< PromptLineNum
? MenuOption
->OptCol
: BeginCol
;
2558 Row
= (OptionLineNum
< PromptLineNum
? OptionLineNum
: PromptLineNum
) + MenuOption
->Row
;
2559 Width
= (UINT16
) (OptionLineNum
< PromptLineNum
? gOptionBlockWidth
: PromptWidth
+ AdjustValue
+ SkipWidth
);
2560 MaxRow
= (OptionLineNum
< PromptLineNum
? PromptLineNum
: OptionLineNum
) + MenuOption
->Row
- 1;
2562 while (Row
<= MaxRow
) {
2563 DisplayMenuString (MenuOption
, Col
, Row
++, L
"", Width
, FALSE
);
2571 Display menu and wait for user to select one menu option, then return it.
2572 If AutoBoot is enabled, then if user doesn't select any option,
2573 after period of time, it will automatically return the first menu option.
2575 @param FormData The current form data info.
2577 @retval EFI_SUCESSS Process the user selection success.
2578 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
2583 IN FORM_DISPLAY_ENGINE_FORM
*FormData
2588 UINTN DistanceValue
;
2597 CHAR16
*StringRightPtr
;
2598 CHAR16
*StringErrorPtr
;
2599 CHAR16
*OptionString
;
2601 CHAR16
*HelpHeaderString
;
2602 CHAR16
*HelpBottomString
;
2611 LIST_ENTRY
*TopOfScreen
;
2612 LIST_ENTRY
*SavedListEntry
;
2613 UI_MENU_OPTION
*MenuOption
;
2614 UI_MENU_OPTION
*NextMenuOption
;
2615 UI_MENU_OPTION
*SavedMenuOption
;
2616 UI_CONTROL_FLAG ControlFlag
;
2617 UI_SCREEN_OPERATION ScreenOperation
;
2618 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
2619 BROWSER_HOT_KEY
*HotKey
;
2620 UINTN HelpPageIndex
;
2621 UINTN HelpPageCount
;
2624 UINTN HelpHeaderLine
;
2625 UINTN HelpBottomLine
;
2626 BOOLEAN MultiHelpPage
;
2627 UINT16 EachLineWidth
;
2628 UINT16 HeaderLineWidth
;
2629 UINT16 BottomLineWidth
;
2630 EFI_STRING_ID HelpInfo
;
2631 UI_EVENT_TYPE EventType
;
2632 BOOLEAN SkipHighLight
;
2633 EFI_HII_VALUE
*StatementValue
;
2635 EventType
= UIEventNone
;
2636 Status
= EFI_SUCCESS
;
2638 HelpHeaderString
= NULL
;
2639 HelpBottomString
= NULL
;
2640 OptionString
= NULL
;
2641 ScreenOperation
= UiNoOperation
;
2649 MultiHelpPage
= FALSE
;
2651 HeaderLineWidth
= 0;
2652 BottomLineWidth
= 0;
2656 SkipHighLight
= FALSE
;
2658 NextMenuOption
= NULL
;
2659 SavedMenuOption
= NULL
;
2663 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
2665 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
2667 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
2668 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
2671 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2672 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
2674 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
2677 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
2678 if (!IsListEmpty (&gMenuOption
)) {
2679 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2680 gUserInput
->SelectedStatement
= NextMenuOption
->ThisTag
;
2683 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
2685 ControlFlag
= CfInitialization
;
2687 switch (ControlFlag
) {
2688 case CfInitialization
:
2689 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
2690 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
2692 // Clear Statement range if different formset is painted.
2695 gStatementDimensions
.LeftColumn
,
2696 gStatementDimensions
.RightColumn
,
2697 TopRow
- SCROLL_ARROW_HEIGHT
,
2698 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2699 GetFieldTextColor ()
2703 ControlFlag
= CfRepaint
;
2707 ControlFlag
= CfRefreshHighLight
;
2717 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2720 // 1. Check whether need to print the arrow up.
2722 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2726 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2727 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2729 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2732 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2734 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2735 TopRow
- SCROLL_ARROW_HEIGHT
,
2738 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2742 // 2.Paint the menu.
2744 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2745 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2746 MenuOption
->Row
= Row
;
2747 MenuOption
->Col
= Col
;
2748 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2749 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2751 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2754 if (MenuOption
->NestInStatement
) {
2755 MenuOption
->Col
+= SUBTITLE_INDENT
;
2759 // Save the highlight menu, will be used in CfRefreshHighLight case.
2761 if (Link
== NewPos
) {
2762 SavedMenuOption
= MenuOption
;
2763 SkipHighLight
= TRUE
;
2766 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2767 Status
= DisplayOneMenu (MenuOption
,
2768 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2769 gStatementDimensions
.LeftColumn
+ gModalSkipColumn
,
2770 Link
== TopOfScreen
? SkipValue
: 0,
2772 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2776 Status
= DisplayOneMenu (MenuOption
,
2777 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2778 gStatementDimensions
.LeftColumn
,
2779 Link
== TopOfScreen
? SkipValue
: 0,
2781 (BOOLEAN
) ((Link
== NewPos
) && IsSelectable(MenuOption
)),
2786 if (EFI_ERROR (Status
)) {
2794 // 3. Update the row info which will be used by next menu.
2796 if (Link
== TopOfScreen
) {
2797 Row
+= MenuOption
->Skip
- SkipValue
;
2799 Row
+= MenuOption
->Skip
;
2802 if (Row
> BottomRow
) {
2803 if (!ValueIsScroll (FALSE
, Link
)) {
2807 Row
= BottomRow
+ 1;
2813 // 3. Menus in this form may not cover all form, clean the remain field.
2815 while (Row
<= BottomRow
) {
2816 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2817 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * gModalSkipColumn
);
2819 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2824 // 4. Print the down arrow row.
2826 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2827 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
+ gModalSkipColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * + gModalSkipColumn
);
2829 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2832 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2834 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2835 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2838 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2845 case CfRefreshHighLight
:
2848 // MenuOption: Last menu option that need to remove hilight
2849 // MenuOption is set to NULL in Repaint
2850 // NewPos: Current menu option that need to hilight
2852 ControlFlag
= CfUpdateHelpString
;
2854 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
2856 if (SkipHighLight
) {
2857 SkipHighLight
= FALSE
;
2858 MenuOption
= SavedMenuOption
;
2859 RefreshKeyHelp(gFormData
, SavedMenuOption
->ThisTag
, FALSE
);
2863 if (IsListEmpty (&gMenuOption
)) {
2865 // No menu option, just update the hotkey filed.
2867 RefreshKeyHelp(gFormData
, NULL
, FALSE
);
2871 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2876 if (NewPos
== TopOfScreen
) {
2882 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2883 if (MenuOption
!= NULL
) {
2885 // Remove the old highlight menu.
2887 Status
= DisplayOneMenu (MenuOption
,
2888 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2889 gStatementDimensions
.LeftColumn
,
2898 // This is the current selected statement
2900 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2901 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2903 if (!IsSelectable (MenuOption
)) {
2907 Status
= DisplayOneMenu (MenuOption
,
2908 MenuOption
->Col
- gStatementDimensions
.LeftColumn
,
2909 gStatementDimensions
.LeftColumn
,
2918 case CfUpdateHelpString
:
2919 ControlFlag
= CfPrepareToReadKey
;
2920 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2925 // NewLine means only update highlight menu (remove old highlight and highlith
2926 // the new one), not need to full repain the form.
2928 if (Repaint
|| NewLine
) {
2929 if (IsListEmpty (&gMenuOption
)) {
2931 // Don't print anything if no mwnu option.
2933 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2936 // Don't print anything if it is a NULL help token
2938 ASSERT(MenuOption
!= NULL
);
2939 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2940 Statement
= MenuOption
->ThisTag
;
2941 StatementValue
= &Statement
->CurrentValue
;
2942 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2943 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)){
2944 StringPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2946 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2949 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)){
2950 StringRightPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2951 StringErrorPtr
= GetToken (STRING_TOKEN (GET_TIME_FAIL
), gHiiHandle
);
2952 StringPtr
= AllocateZeroPool ((StrLen (StringRightPtr
) + StrLen (StringErrorPtr
)+ 1 ) * sizeof (CHAR16
));
2953 StrCpyS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringRightPtr
);
2954 StrCatS (StringPtr
, StrLen (StringRightPtr
) + StrLen (StringErrorPtr
) + 1, StringErrorPtr
);
2955 FreePool (StringRightPtr
);
2956 FreePool (StringErrorPtr
);
2958 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2963 RowCount
= BottomRow
- TopRow
+ 1;
2966 // 1.Calculate how many line the help string need to print.
2968 if (HelpString
!= NULL
) {
2969 FreePool (HelpString
);
2972 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2973 FreePool (StringPtr
);
2975 if (HelpLine
> RowCount
) {
2976 MultiHelpPage
= TRUE
;
2977 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2978 if (HelpHeaderString
!= NULL
) {
2979 FreePool (HelpHeaderString
);
2980 HelpHeaderString
= NULL
;
2982 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2983 FreePool (StringPtr
);
2984 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2985 if (HelpBottomString
!= NULL
) {
2986 FreePool (HelpBottomString
);
2987 HelpBottomString
= NULL
;
2989 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2990 FreePool (StringPtr
);
2992 // Calculate the help page count.
2994 if (HelpLine
> 2 * RowCount
- 2) {
2995 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2996 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) != 0) {
3003 MultiHelpPage
= FALSE
;
3008 // Check whether need to show the 'More(U/u)' at the begin.
3009 // Base on current direct info, here shows aligned to the right side of the column.
3010 // If the direction is multi line and aligned to right side may have problem, so
3011 // add ASSERT code here.
3013 if (HelpPageIndex
> 0) {
3014 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3015 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
3016 ASSERT (HelpHeaderLine
== 1);
3017 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3018 PrintStringAtWithWidth (
3019 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3025 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
3027 &HelpHeaderString
[Index
* HeaderLineWidth
]
3032 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
3034 // Print the help string info.
3036 if (!MultiHelpPage
) {
3037 for (Index
= 0; Index
< HelpLine
; Index
++) {
3038 PrintStringAtWithWidth (
3039 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3041 &HelpString
[Index
* EachLineWidth
],
3045 for (; Index
< RowCount
; Index
++) {
3046 PrintStringAtWithWidth (
3047 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3053 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3055 if (HelpPageIndex
== 0) {
3056 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
3057 PrintStringAtWithWidth (
3058 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3060 &HelpString
[Index
* EachLineWidth
],
3065 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
3066 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
3067 PrintStringAtWithWidth (
3068 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3069 Index
+ TopRow
+ HelpHeaderLine
,
3070 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
3074 if (HelpPageIndex
== HelpPageCount
- 1) {
3075 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
3076 PrintStringAtWithWidth (
3077 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3078 Index
+ TopRow
+ HelpHeaderLine
,
3083 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
3089 // Check whether need to print the 'More(D/d)' at the bottom.
3090 // Base on current direct info, here shows aligned to the right side of the column.
3091 // If the direction is multi line and aligned to right side may have problem, so
3092 // add ASSERT code here.
3094 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
3095 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
3096 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
3097 ASSERT (HelpBottomLine
== 1);
3098 ASSERT (GetStringWidth (HelpBottomString
) / 2 < ((UINT32
) gHelpBlockWidth
- 1));
3099 PrintStringAtWithWidth (
3100 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
3101 BottomRow
+ Index
- HelpBottomLine
+ 1,
3106 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
3107 BottomRow
+ Index
- HelpBottomLine
+ 1,
3108 &HelpBottomString
[Index
* BottomLineWidth
]
3113 // Reset this flag every time we finish using it.
3119 case CfPrepareToReadKey
:
3120 ControlFlag
= CfReadKey
;
3121 ScreenOperation
= UiNoOperation
;
3125 ControlFlag
= CfScreenOperation
;
3128 // Wait for user's selection
3131 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3132 if (!EFI_ERROR (Status
)) {
3133 EventType
= UIEventKey
;
3138 // If we encounter error, continue to read another key in.
3140 if (Status
!= EFI_NOT_READY
) {
3144 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
3145 if (EventType
== UIEventKey
) {
3146 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3151 if (EventType
== UIEventDriver
) {
3153 gUserInput
->Action
= BROWSER_ACTION_NONE
;
3154 ControlFlag
= CfExit
;
3158 if (EventType
== UIEventTimeOut
) {
3159 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3160 ControlFlag
= CfExit
;
3164 switch (Key
.UnicodeChar
) {
3165 case CHAR_CARRIAGE_RETURN
:
3166 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3167 ControlFlag
= CfReadKey
;
3171 ScreenOperation
= UiSelect
;
3176 // We will push the adjustment of these numeric values directly to the input handler
3177 // NOTE: we won't handle manual input numeric
3182 // If the screen has no menu items, and the user didn't select UiReset
3183 // ignore the selection and go back to reading keys.
3185 ASSERT(MenuOption
!= NULL
);
3186 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
3187 ControlFlag
= CfReadKey
;
3191 Statement
= MenuOption
->ThisTag
;
3192 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
3193 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3194 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
3196 if (Key
.UnicodeChar
== '+') {
3197 gDirection
= SCAN_RIGHT
;
3199 gDirection
= SCAN_LEFT
;
3202 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3203 if (OptionString
!= NULL
) {
3204 FreePool (OptionString
);
3206 if (EFI_ERROR (Status
)) {
3208 // Repaint to clear possible error prompt pop-up
3213 ControlFlag
= CfExit
;
3219 ScreenOperation
= UiUp
;
3224 ScreenOperation
= UiDown
;
3228 if(IsListEmpty (&gMenuOption
)) {
3229 ControlFlag
= CfReadKey
;
3233 ASSERT(MenuOption
!= NULL
);
3234 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
3235 ScreenOperation
= UiSelect
;
3241 if (!MultiHelpPage
) {
3242 ControlFlag
= CfReadKey
;
3245 ControlFlag
= CfUpdateHelpString
;
3246 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
3251 if (!MultiHelpPage
) {
3252 ControlFlag
= CfReadKey
;
3255 ControlFlag
= CfUpdateHelpString
;
3256 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
3260 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
3261 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
3262 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
3267 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
3269 // ModalForm has no ESC key and Hot Key.
3271 ControlFlag
= CfReadKey
;
3272 } else if (Index
== mScanCodeNumber
) {
3274 // Check whether Key matches the registered hot key.
3277 HotKey
= GetHotKeyFromRegisterList (&Key
);
3278 if (HotKey
!= NULL
) {
3279 ScreenOperation
= UiHotKey
;
3286 case CfScreenOperation
:
3287 if ((ScreenOperation
!= UiReset
) && (ScreenOperation
!= UiHotKey
)) {
3289 // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
3290 // ignore the selection and go back to reading keys.
3292 if (IsListEmpty (&gMenuOption
)) {
3293 ControlFlag
= CfReadKey
;
3299 Index
< ARRAY_SIZE (gScreenOperationToControlFlag
);
3302 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
3303 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
3310 ControlFlag
= CfRepaint
;
3312 ASSERT(MenuOption
!= NULL
);
3313 Statement
= MenuOption
->ThisTag
;
3314 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
3318 switch (Statement
->OpCode
->OpCode
) {
3319 case EFI_IFR_REF_OP
:
3320 case EFI_IFR_ACTION_OP
:
3321 case EFI_IFR_RESET_BUTTON_OP
:
3322 ControlFlag
= CfExit
;
3327 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
3329 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
3330 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
3332 if (OptionString
!= NULL
) {
3333 FreePool (OptionString
);
3336 if (EFI_ERROR (Status
)) {
3339 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
3342 ControlFlag
= CfExit
;
3350 // We come here when someone press ESC
3351 // If the policy is not exit front page when user press ESC, process here.
3353 if (!FormExitPolicy()) {
3356 ControlFlag
= CfRepaint
;
3360 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
3361 ControlFlag
= CfExit
;
3365 ControlFlag
= CfRepaint
;
3367 ASSERT (HotKey
!= NULL
);
3369 if (FxConfirmPopup(HotKey
->Action
)) {
3370 gUserInput
->Action
= HotKey
->Action
;
3371 if ((HotKey
->Action
& BROWSER_ACTION_DEFAULT
) == BROWSER_ACTION_DEFAULT
) {
3372 gUserInput
->DefaultId
= HotKey
->DefaultId
;
3374 ControlFlag
= CfExit
;
3378 ControlFlag
= CfRepaint
;
3384 ControlFlag
= CfRepaint
;
3385 ASSERT(MenuOption
!= NULL
);
3386 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3387 if (MenuOption
->Sequence
!= 0) {
3389 // In the middle or tail of the Date/Time op-code set, go left.
3391 ASSERT(NewPos
!= NULL
);
3392 NewPos
= NewPos
->BackLink
;
3398 ControlFlag
= CfRepaint
;
3399 ASSERT(MenuOption
!= NULL
);
3400 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
3401 if (MenuOption
->Sequence
!= 2) {
3403 // In the middle or tail of the Date/Time op-code set, go left.
3405 ASSERT(NewPos
!= NULL
);
3406 NewPos
= NewPos
->ForwardLink
;
3412 ControlFlag
= CfRepaint
;
3415 SavedListEntry
= NewPos
;
3416 ASSERT(NewPos
!= NULL
);
3418 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3419 ASSERT (MenuOption
!= NULL
);
3422 // Adjust Date/Time position before we advance forward.
3424 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3426 NewPos
= NewPos
->BackLink
;
3428 // Find next selectable menu or the first menu beyond current form.
3430 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
, FALSE
);
3431 if (Difference
< 0) {
3433 // We hit the begining MenuOption that can be focused
3434 // so we simply scroll to the top.
3437 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3438 TopOfScreen
= gMenuOption
.ForwardLink
;
3439 NewPos
= SavedListEntry
;
3443 // Scroll up to the last page when we have arrived at top page.
3445 TopOfScreen
= FindTopOfScreenMenu (gMenuOption
.BackLink
, BottomRow
- TopRow
, &SkipValue
);
3446 NewPos
= gMenuOption
.BackLink
;
3447 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3450 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3452 if (MenuOption
->Row
< TopRow
+ Difference
+ NextMenuOption
->Skip
) {
3454 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
3456 TopOfScreen
= NewPos
;
3462 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3464 // BottomRow - TopRow + 1 means the total rows current forms supported.
3465 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3466 // and new top menu. New top menu will all shows in next form, but last highlight menu
3467 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3468 // last highlight menu.
3470 if (!IsSelectable(NextMenuOption
) && IsSelectable(MenuOption
) &&
3471 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3472 NewPos
= SavedListEntry
;
3476 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3479 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3481 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3482 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3484 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3489 // SkipValue means lines is skipped when show the top menu option.
3491 ControlFlag
= CfRepaint
;
3497 // First minus the menu of the top screen, it's value is SkipValue.
3499 if (SkipValue
>= BottomRow
- TopRow
+ 1) {
3501 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
3502 // form of options to be show, so just update the SkipValue to show the next
3503 // parts of options.
3505 SkipValue
-= BottomRow
- TopRow
+ 1;
3506 NewPos
= TopOfScreen
;
3509 Index
= (BottomRow
+ 1) - SkipValue
- TopRow
;
3512 TopOfScreen
= FindTopOfScreenMenu(TopOfScreen
, Index
, &SkipValue
);
3513 NewPos
= TopOfScreen
;
3514 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, FALSE
);
3516 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3519 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3520 // Don't do this when we are already in the first page.
3522 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3523 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3525 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3530 // SkipValue means lines is skipped when show the top menu option.
3532 ControlFlag
= CfRepaint
;
3537 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3538 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
3540 // Count to the menu option which will show at the top of the next form.
3542 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
3543 Link
= Link
->ForwardLink
;
3544 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3545 Index
= Index
+ NextMenuOption
->Skip
;
3548 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
3550 // Highlight on the last menu which can be highlight.
3553 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
, TRUE
);
3556 // Calculate the skip line for top of screen menu.
3558 if (Link
== TopOfScreen
) {
3560 // The top of screen menu option occupies the entire form.
3562 SkipValue
+= BottomRow
- TopRow
+ 1;
3564 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
3569 // Move to the Next selectable menu.
3571 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
, TRUE
);
3575 // Save the menu as the next highlight menu.
3579 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3582 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3583 // Don't do this when we are already in the last page.
3585 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3586 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3588 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3593 // SkipValue means lines is skipped when show the top menu option.
3594 // NewPos points to the menu which is highlighted now.
3596 ControlFlag
= CfRepaint
;
3599 if (NewPos
== TopOfScreen
) {
3605 SavedListEntry
= NewPos
;
3607 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3608 // to be one that progresses to the next set of op-codes, we need to advance to the last
3609 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3610 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3611 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3612 // the Date/Time op-code.
3614 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3616 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3617 NewPos
= NewPos
->ForwardLink
;
3619 // Find the next selectable menu.
3621 if (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
> BottomRow
+ 1) {
3622 if (gMenuOption
.ForwardLink
== NewPos
|| &gMenuOption
== NewPos
) {
3628 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
+ 1 - (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
), FALSE
);
3630 if (Difference
< 0) {
3632 // Scroll to the first page.
3634 if (TopOfScreen
!= gMenuOption
.ForwardLink
|| SkipValue
!= 0) {
3635 TopOfScreen
= gMenuOption
.ForwardLink
;
3639 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3641 NewPos
= gMenuOption
.ForwardLink
;
3642 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
, TRUE
);
3646 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3648 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3649 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3651 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3656 // Get next selected menu info.
3658 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3659 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3660 if (NextMenuOption
->Row
== 0) {
3661 UpdateOptionSkipLines (NextMenuOption
);
3665 // Calculate new highlight menu end row.
3667 Temp
= (MenuOption
->Row
+ MenuOption
->Skip
- Temp2
) + Difference
+ NextMenuOption
->Skip
- 1;
3668 if (Temp
> BottomRow
) {
3670 // Get the top screen menu info.
3672 AdjustDateAndTimePosition (FALSE
, &TopOfScreen
);
3673 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3676 // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
3677 // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
3679 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3681 // Skip the top op-code
3683 TopOfScreen
= TopOfScreen
->ForwardLink
;
3684 DistanceValue
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3686 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3689 // If we have a remainder, skip that many more op-codes until we drain the remainder
3690 // Special case is the selected highlight menu has more than one form of menus.
3692 while (DistanceValue
>= SavedMenuOption
->Skip
&& TopOfScreen
!= NewPos
) {
3694 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3696 DistanceValue
= DistanceValue
- (INTN
) SavedMenuOption
->Skip
;
3697 TopOfScreen
= TopOfScreen
->ForwardLink
;
3698 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3701 // Since we will act on this op-code in the next routine, and increment the
3702 // SkipValue, set the skips to one less than what is required.
3704 if (TopOfScreen
!= NewPos
) {
3705 SkipValue
= DistanceValue
;
3711 // Since we will act on this op-code in the next routine, and increment the
3712 // SkipValue, set the skips to one less than what is required.
3714 SkipValue
+= Temp
- BottomRow
;
3717 } else if (!IsSelectable (NextMenuOption
)) {
3719 // Continue to go down until scroll to next page or the selectable option is found.
3721 ScreenOperation
= UiDown
;
3722 ControlFlag
= CfScreenOperation
;
3726 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3729 // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
3731 // BottomRow - TopRow + 1 means the total rows current forms supported.
3732 // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
3733 // and new top menu. New top menu will all shows in next form, but last highlight menu
3734 // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
3735 // last highlight menu.
3737 if (!IsSelectable (NextMenuOption
) && IsSelectable (MenuOption
) &&
3738 (BottomRow
- TopRow
+ 1 >= Difference
+ NextMenuOption
->Skip
+ 1)) {
3739 NewPos
= SavedListEntry
;
3742 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3745 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3747 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3748 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3750 UpdateHighlightMenuInfo(NewPos
, TopOfScreen
, SkipValue
);
3753 case CfUiNoOperation
:
3754 ControlFlag
= CfRepaint
;
3758 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3759 if (HelpString
!= NULL
) {
3760 FreePool (HelpString
);
3762 if (HelpHeaderString
!= NULL
) {
3763 FreePool (HelpHeaderString
);
3765 if (HelpBottomString
!= NULL
) {
3766 FreePool (HelpBottomString
);
3777 Free the UI Menu Option structure data.
3779 @param MenuOptionList Point to the menu option list which need to be free.
3784 LIST_ENTRY
*MenuOptionList
3788 UI_MENU_OPTION
*Option
;
3791 // Free menu option list
3793 while (!IsListEmpty (MenuOptionList
)) {
3794 Link
= GetFirstNode (MenuOptionList
);
3795 Option
= MENU_OPTION_FROM_LINK (Link
);
3796 if (Option
->Description
!= NULL
){
3797 FreePool(Option
->Description
);
3799 RemoveEntryList (&Option
->Link
);
3806 Base on the browser status info to show an pop up message.
3810 BrowserStatusProcess (
3816 EFI_EVENT WaitList
[2];
3817 EFI_EVENT RefreshIntervalEvent
;
3818 EFI_EVENT TimeOutEvent
;
3822 WARNING_IF_CONTEXT EventContext
;
3823 EFI_IFR_OP_HEADER
*OpCodeBuf
;
3824 EFI_STRING_ID StringToken
;
3825 CHAR16 DiscardChange
;
3826 CHAR16 JumpToFormSet
;
3827 CHAR16
*PrintString
;
3829 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3834 TimeOutEvent
= NULL
;
3835 RefreshIntervalEvent
= NULL
;
3837 if (gFormData
->HighLightedStatement
!= NULL
) {
3838 OpCodeBuf
= gFormData
->HighLightedStatement
->OpCode
;
3841 if (gFormData
->BrowserStatus
== (BROWSER_WARNING_IF
)) {
3842 ASSERT (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_WARNING_IF_OP
);
3844 TimeOut
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->TimeOut
;
3845 StringToken
= ((EFI_IFR_WARNING_IF
*) OpCodeBuf
)->Warning
;
3848 if ((gFormData
->BrowserStatus
== (BROWSER_NO_SUBMIT_IF
)) &&
3849 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_NO_SUBMIT_IF_OP
)) {
3850 StringToken
= ((EFI_IFR_NO_SUBMIT_IF
*) OpCodeBuf
)->Error
;
3851 } else if ((gFormData
->BrowserStatus
== (BROWSER_INCONSISTENT_IF
)) &&
3852 (OpCodeBuf
!= NULL
&& OpCodeBuf
->OpCode
== EFI_IFR_INCONSISTENT_IF_OP
)) {
3853 StringToken
= ((EFI_IFR_INCONSISTENT_IF
*) OpCodeBuf
)->Error
;
3857 if (StringToken
!= 0) {
3858 ErrorInfo
= GetToken (StringToken
, gFormData
->HiiHandle
);
3859 } else if (gFormData
->ErrorString
!= NULL
) {
3861 // Only used to compatible with old setup browser.
3862 // Not use this field in new browser core.
3864 ErrorInfo
= gFormData
->ErrorString
;
3866 switch (gFormData
->BrowserStatus
) {
3867 case BROWSER_SUBMIT_FAIL
:
3868 ErrorInfo
= gSaveFailed
;
3871 case BROWSER_FORM_NOT_FOUND
:
3872 ErrorInfo
= gFormNotFound
;
3875 case BROWSER_FORM_SUPPRESS
:
3876 ErrorInfo
= gFormSuppress
;
3879 case BROWSER_PROTOCOL_NOT_FOUND
:
3880 ErrorInfo
= gProtocolNotFound
;
3883 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3884 ErrorInfo
= gNoSubmitIfFailed
;
3887 case BROWSER_RECONNECT_FAIL
:
3888 ErrorInfo
= gReconnectFail
;
3891 case BROWSER_RECONNECT_SAVE_CHANGES
:
3892 ErrorInfo
= gReconnectConfirmChanges
;
3895 case BROWSER_RECONNECT_REQUIRED
:
3896 ErrorInfo
= gReconnectRequired
;
3900 ErrorInfo
= gBrowserError
;
3905 switch (gFormData
->BrowserStatus
) {
3906 case BROWSER_SUBMIT_FAIL
:
3907 case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF
:
3908 case BROWSER_RECONNECT_SAVE_CHANGES
:
3909 ASSERT (gUserInput
!= NULL
);
3910 if (gFormData
->BrowserStatus
== (BROWSER_SUBMIT_FAIL
)) {
3911 PrintString
= gSaveProcess
;
3912 JumpToFormSet
= gJumpToFormSet
[0];
3913 DiscardChange
= gDiscardChange
[0];
3914 } else if (gFormData
->BrowserStatus
== (BROWSER_RECONNECT_SAVE_CHANGES
)){
3915 PrintString
= gChangesOpt
;
3916 JumpToFormSet
= gConfirmOptYes
[0];
3917 DiscardChange
= gConfirmOptNo
[0];
3919 PrintString
= gSaveNoSubmitProcess
;
3920 JumpToFormSet
= gCheckError
[0];
3921 DiscardChange
= gDiscardChange
[0];
3925 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, PrintString
, gEmptyString
, NULL
);
3926 } while (((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) &&
3927 ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) != (JumpToFormSet
| UPPER_LOWER_CASE_OFFSET
)));
3929 if ((Key
.UnicodeChar
| UPPER_LOWER_CASE_OFFSET
) == (DiscardChange
| UPPER_LOWER_CASE_OFFSET
)) {
3930 gUserInput
->Action
= BROWSER_ACTION_DISCARD
;
3932 gUserInput
->Action
= BROWSER_ACTION_GOTO
;
3939 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3940 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3942 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
3943 ASSERT_EFI_ERROR (Status
);
3945 EventContext
.SyncEvent
= TimeOutEvent
;
3946 EventContext
.TimeOut
= &TimeOut
;
3947 EventContext
.ErrorInfo
= ErrorInfo
;
3949 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
3950 ASSERT_EFI_ERROR (Status
);
3953 // Show the dialog first to avoid long time not reaction.
3955 gBS
->SignalEvent (RefreshIntervalEvent
);
3957 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
3958 ASSERT_EFI_ERROR (Status
);
3961 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3962 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3966 if (Status
!= EFI_NOT_READY
) {
3970 WaitList
[0] = TimeOutEvent
;
3971 WaitList
[1] = gST
->ConIn
->WaitForKey
;
3973 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
3974 ASSERT_EFI_ERROR (Status
);
3978 // Timeout occur, close the hoot time out event.
3984 gBS
->CloseEvent (TimeOutEvent
);
3985 gBS
->CloseEvent (RefreshIntervalEvent
);
3990 if (StringToken
!= 0) {
3991 FreePool (ErrorInfo
);
3996 Display one form, and return user input.
3998 @param FormData Form Data to be shown.
3999 @param UserInputData User input data.
4001 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
4002 2.Error info has show and return.
4003 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
4004 @retval EFI_NOT_FOUND New form data has some error.
4009 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
4010 OUT USER_INPUT
*UserInputData
4015 ASSERT (FormData
!= NULL
);
4016 if (FormData
== NULL
) {
4017 return EFI_INVALID_PARAMETER
;
4020 gUserInput
= UserInputData
;
4021 gFormData
= FormData
;
4024 // Process the status info first.
4026 BrowserStatusProcess();
4027 if (gFormData
->BrowserStatus
!= BROWSER_SUCCESS
) {
4029 // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
4034 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
4035 if (EFI_ERROR (Status
)) {
4040 // Global Widths should be initialized before any MenuOption creation
4041 // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
4045 // |<-.->|<-.........->|<- .........->|<-...........->|
4046 // Skip Prompt Option Help
4048 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3) + 1;
4049 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- 1 - LEFT_SKIPPED_COLUMNS
);
4050 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * (gOptionBlockWidth
- 1) - 1);
4052 ConvertStatementToMenu();
4055 // Check whether layout is changed.
4058 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
4059 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
4060 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
4061 mStatementLayoutIsChanged
= TRUE
;
4063 mStatementLayoutIsChanged
= FALSE
;
4066 Status
= UiDisplayMenu(FormData
);
4069 // Backup last form info.
4071 mIsFirstForm
= FALSE
;
4072 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
4073 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
4074 gOldFormEntry
.FormId
= FormData
->FormId
;
4077 //Free the Ui menu option list.
4079 FreeMenuOptionData(&gMenuOption
);
4085 Clear Screen to the initial state.
4089 DriverClearDisplayPage (
4093 ClearDisplayPage ();
4094 mIsFirstForm
= TRUE
;
4098 Set Buffer to Value for Size bytes.
4100 @param Buffer Memory to set.
4101 @param Size Number of bytes to set
4102 @param Value Value of the set operation.
4115 while ((Size
--) != 0) {
4121 Initialize Setup Browser driver.
4123 @param ImageHandle The image handle.
4124 @param SystemTable The system table.
4126 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
4127 @return Other value if failed to initialize the Setup Browser module.
4132 InitializeDisplayEngine (
4133 IN EFI_HANDLE ImageHandle
,
4134 IN EFI_SYSTEM_TABLE
*SystemTable
4138 EFI_INPUT_KEY HotKey
;
4139 EFI_STRING NewString
;
4140 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
4143 // Publish our HII data
4145 gHiiHandle
= HiiAddPackages (
4146 &gDisplayEngineGuid
,
4148 DisplayEngineStrings
,
4151 ASSERT (gHiiHandle
!= NULL
);
4154 // Install Form Display protocol
4156 Status
= gBS
->InstallProtocolInterface (
4157 &mPrivateData
.Handle
,
4158 &gEdkiiFormDisplayEngineProtocolGuid
,
4159 EFI_NATIVE_INTERFACE
,
4160 &mPrivateData
.FromDisplayProt
4162 ASSERT_EFI_ERROR (Status
);
4164 InitializeDisplayStrings();
4166 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
4167 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
4170 // Use BrowserEx2 protocol to register HotKey.
4172 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
4173 if (!EFI_ERROR (Status
)) {
4175 // Register the default HotKey F9 and F10 again.
4177 HotKey
.UnicodeChar
= CHAR_NULL
;
4178 HotKey
.ScanCode
= SCAN_F10
;
4179 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
4180 ASSERT (NewString
!= NULL
);
4181 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
4183 HotKey
.ScanCode
= SCAN_F9
;
4184 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
4185 ASSERT (NewString
!= NULL
);
4186 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
4193 This is the default unload handle for display core drivers.
4195 @param[in] ImageHandle The drivers' driver image.
4197 @retval EFI_SUCCESS The image is unloaded.
4198 @retval Others Failed to unload the image.
4203 UnloadDisplayEngine (
4204 IN EFI_HANDLE ImageHandle
4207 HiiRemovePackages(gHiiHandle
);
4209 FreeDisplayStrings ();
4211 if (gHighligthMenuInfo
.HLTOpCode
!= NULL
) {
4212 FreePool (gHighligthMenuInfo
.HLTOpCode
);
4215 if (gHighligthMenuInfo
.TOSOpCode
!= NULL
) {
4216 FreePool (gHighligthMenuInfo
.TOSOpCode
);