2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "FormDisplay.h"
18 // Search table for UiDisplayMenu()
20 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
51 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
53 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
96 EFI_GUID gDisplayEngineGuid
= {
97 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
100 FORM_ENTRY_INFO gFormEntryInfo
;
102 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
103 BOOLEAN mStatementLayoutIsChanged
= TRUE
;
104 USER_INPUT
*gUserInput
;
105 FORM_DISPLAY_ENGINE_FORM
*gFormData
;
106 EFI_HII_HANDLE gHiiHandle
;
108 LIST_ENTRY gMenuOption
;
109 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo
= {0};
110 BOOLEAN mIsFirstForm
= TRUE
;
111 FORM_ENTRY_INFO gOldFormEntry
= {0};
114 // Browser Global Strings
116 CHAR16
*gFormNotFound
;
118 CHAR16
*gBrwoserError
;
120 CHAR16
*gPromptForData
;
121 CHAR16
*gPromptForPassword
;
122 CHAR16
*gPromptForNewPassword
;
123 CHAR16
*gConfirmPassword
;
124 CHAR16
*gConfirmError
;
125 CHAR16
*gPassowordInvalid
;
127 CHAR16
*gEmptyString
;
129 CHAR16
*gOptionMismatch
;
130 CHAR16
*gFormSuppress
;
131 CHAR16
*gProtocolNotFound
;
133 CHAR16 gPromptBlockWidth
;
134 CHAR16 gOptionBlockWidth
;
135 CHAR16 gHelpBlockWidth
;
136 CHAR16
*mUnknownString
;
138 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
139 FORM_DISPLAY_DRIVER_SIGNATURE
,
143 DriverClearDisplayPage
,
150 Get the string based on the StringId and HII Package List Handle.
152 @param Token The String's ID.
153 @param HiiHandle The package list in the HII database to search for
154 the specified string.
156 @return The output string.
161 IN EFI_STRING_ID Token
,
162 IN EFI_HII_HANDLE HiiHandle
167 String
= HiiGetString (HiiHandle
, Token
, NULL
);
168 if (String
== NULL
) {
169 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
170 ASSERT (String
!= NULL
);
173 return (CHAR16
*) String
;
178 Initialize the HII String Token to the correct values.
182 InitializeDisplayStrings (
186 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
187 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
188 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
189 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
190 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
191 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
192 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
193 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
194 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
195 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
196 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
197 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
198 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
199 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
200 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
201 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
202 gBrwoserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
206 Free up the resource allocated for all strings required
215 FreePool (mUnknownString
);
216 FreePool (gEmptyString
);
217 FreePool (gSaveFailed
);
218 FreePool (gPromptForData
);
219 FreePool (gPromptForPassword
);
220 FreePool (gPromptForNewPassword
);
221 FreePool (gConfirmPassword
);
222 FreePool (gConfirmError
);
223 FreePool (gPassowordInvalid
);
224 FreePool (gPressEnter
);
225 FreePool (gMiniString
);
226 FreePool (gOptionMismatch
);
227 FreePool (gFormSuppress
);
228 FreePool (gProtocolNotFound
);
229 FreePool (gBrwoserError
);
230 FreePool (gNoSubmitIf
);
231 FreePool (gFormNotFound
);
235 Get prompt string id from the opcode data buffer.
237 @param OpCode The input opcode buffer.
239 @return The prompt string id.
244 IN EFI_IFR_OP_HEADER
*OpCode
247 EFI_IFR_STATEMENT_HEADER
*Header
;
249 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
253 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
255 return Header
->Prompt
;
259 Get the supported width for a particular op-code
261 @param Statement The curent statement.
263 @return Returns the number of CHAR16 characters that is support.
268 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
274 EFI_IFR_TEXT
*TestOp
;
279 // See if the second text parameter is really NULL
281 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
282 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
283 if (TestOp
->TextTwo
!= 0) {
284 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
285 Size
= StrLen (String
);
290 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
291 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
292 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
293 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
294 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
296 // Allow a wide display if text op-code and no secondary text op-code
298 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
300 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
302 Width
= (UINT16
) gPromptBlockWidth
;
305 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
309 Will copy LineWidth amount of a string in the OutputString buffer and return the
310 number of CHAR16 characters that were copied into the OutputString buffer.
311 The output string format is:
312 Glyph Info + String info + '\0'.
314 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
316 @param InputString String description for this option.
317 @param LineWidth Width of the desired string to extract in CHAR16
319 @param GlyphWidth The glyph width of the begin of the char in the string.
320 @param Index Where in InputString to start the copy process
321 @param OutputString Buffer to copy the string into
323 @return Returns the number of CHAR16 characters that were copied into the OutputString
324 buffer, include extra glyph info and '\0' info.
329 IN CHAR16
*InputString
,
331 IN OUT UINT16
*GlyphWidth
,
333 OUT CHAR16
**OutputString
338 UINT16 OriginalGlyphWidth
;
340 UINT16 LastSpaceOffset
;
341 UINT16 LastGlyphWidth
;
343 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
347 if (LineWidth
== 0 || *GlyphWidth
== 0) {
352 // Save original glyph width.
354 OriginalGlyphWidth
= *GlyphWidth
;
355 LastGlyphWidth
= OriginalGlyphWidth
;
360 // 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.
361 // To avoid displaying this empty line in screen, just skip the two CHARs here.
363 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
368 // Fast-forward the string and see if there is a carriage-return in the string
370 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
371 switch (InputString
[*Index
+ StrOffset
]) {
380 case CHAR_CARRIAGE_RETURN
:
387 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
390 // Record the last space info in this line. Will be used in rewind.
392 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
393 LastSpaceOffset
= StrOffset
;
394 LastGlyphWidth
= *GlyphWidth
;
405 // Rewind the string from the maximum size until we see a space to break the line
407 if (GlyphOffset
> LineWidth
) {
409 // Rewind the string to last space char in this line.
411 if (LastSpaceOffset
!= 0) {
412 StrOffset
= LastSpaceOffset
;
413 *GlyphWidth
= LastGlyphWidth
;
416 // Roll back to last char in the line width.
423 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
425 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
430 // Need extra glyph info and '\0' info, so +2.
432 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
433 if (*OutputString
== NULL
) {
438 // Save the glyph info at the begin of the string, will used by Print function.
440 if (OriginalGlyphWidth
== 1) {
441 *(*OutputString
) = NARROW_CHAR
;
443 *(*OutputString
) = WIDE_CHAR
;
446 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
448 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
450 // Skip the space info at the begin of next line.
452 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
453 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
455 // Skip the /n or /n/r info.
457 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
458 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
460 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
462 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
464 // Skip the /r or /r/n info.
466 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
467 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
469 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
472 *Index
= (UINT16
) (*Index
+ StrOffset
);
476 // Include extra glyph info and '\0' info, so +2.
478 return StrOffset
+ 2;
482 Add one menu option by specified description and context.
484 @param Statement Statement of this Menu Option.
485 @param MenuItemCount The index for this Option in the Menu.
486 @param NestIn Whether this statement is nest in another statement.
491 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
492 IN UINT16
*MenuItemCount
,
496 UI_MENU_OPTION
*MenuOption
;
500 UINT16 NumberOfLines
;
504 CHAR16
*OutputString
;
505 EFI_STRING_ID PromptId
;
513 PromptId
= GetPrompt (Statement
->OpCode
);
514 ASSERT (PromptId
!= 0);
516 String
= GetToken (PromptId
, gFormData
->HiiHandle
);
517 ASSERT (String
!= NULL
);
519 Width
= GetWidth (Statement
);
520 for (; GetLineByWidth (String
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
522 // If there is more string to process print on the next row and increment the Skip value
524 if (StrLen (&String
[ArrayEntry
]) != 0) {
527 FreePool (OutputString
);
530 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
532 // Add three MenuOptions for Date/Time
533 // Data format : [01/02/2004] [11:22:33]
534 // Line number : 0 0 1 0 0 1
540 for (Index
= 0; Index
< Count
; Index
++) {
541 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
544 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
545 MenuOption
->Description
= String
;
546 MenuOption
->Handle
= gFormData
->HiiHandle
;
547 MenuOption
->ThisTag
= Statement
;
548 MenuOption
->NestInStatement
= NestIn
;
549 MenuOption
->EntryNumber
= *MenuItemCount
;
553 // Override LineNumber for the MenuOption in Date/Time sequence
555 MenuOption
->Skip
= 1;
557 MenuOption
->Skip
= NumberOfLines
;
559 MenuOption
->Sequence
= Index
;
561 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
562 MenuOption
->GrayOut
= TRUE
;
564 MenuOption
->GrayOut
= FALSE
;
567 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
568 MenuOption
->GrayOut
= TRUE
;
572 // If the form or the question has the lock attribute, deal same as grayout.
574 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
575 MenuOption
->GrayOut
= TRUE
;
578 switch (Statement
->OpCode
->OpCode
) {
579 case EFI_IFR_ORDERED_LIST_OP
:
580 case EFI_IFR_ONE_OF_OP
:
581 case EFI_IFR_NUMERIC_OP
:
582 case EFI_IFR_TIME_OP
:
583 case EFI_IFR_DATE_OP
:
584 case EFI_IFR_CHECKBOX_OP
:
585 case EFI_IFR_PASSWORD_OP
:
586 case EFI_IFR_STRING_OP
:
588 // User could change the value of these items
590 MenuOption
->IsQuestion
= TRUE
;
592 case EFI_IFR_TEXT_OP
:
593 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
595 // Initializing GrayOut option as TRUE for Text setup options
596 // so that those options will be Gray in colour and un selectable.
598 MenuOption
->GrayOut
= TRUE
;
602 MenuOption
->IsQuestion
= FALSE
;
606 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
607 MenuOption
->ReadOnly
= TRUE
;
608 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
609 MenuOption
->GrayOut
= TRUE
;
613 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
620 Create the menu list base on the form data info.
624 ConvertStatementToMenu (
628 UINT16 MenuItemCount
;
630 LIST_ENTRY
*NestLink
;
631 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
632 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
635 InitializeListHead (&gMenuOption
);
637 Link
= GetFirstNode (&gFormData
->StatementListHead
);
638 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
639 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
640 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
643 // Skip the opcode not recognized by Display core.
645 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
649 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
652 // Check the statement nest in this host statement.
654 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
655 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
656 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
657 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
659 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
665 Count the storage space of a Unicode string.
667 This function handles the Unicode string with NARROW_CHAR
668 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
669 does not count in the resultant output. If a WIDE_CHAR is
670 hit, then 2 Unicode character will consume an output storage
671 space with size of CHAR16 till a NARROW_CHAR is hit.
673 If String is NULL, then ASSERT ().
675 @param String The input string to be counted.
677 @return Storage space for the input string.
687 UINTN IncrementValue
;
689 ASSERT (String
!= NULL
);
690 if (String
== NULL
) {
700 // Advance to the null-terminator or to the first width directive
703 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
704 Index
++, Count
= Count
+ IncrementValue
709 // We hit the null-terminator, we now have a count
711 if (String
[Index
] == 0) {
715 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
716 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
718 if (String
[Index
] == NARROW_CHAR
) {
720 // Skip to the next character
726 // Skip to the next character
731 } while (String
[Index
] != 0);
734 // Increment by one to include the null-terminator in the size
738 return Count
* sizeof (CHAR16
);
742 Base on the input option string to update the skip value for a menu option.
744 @param MenuOption The MenuOption to be checked.
745 @param OptionString The input option string.
749 UpdateSkipInfoForMenu (
750 IN UI_MENU_OPTION
*MenuOption
,
751 IN CHAR16
*OptionString
757 CHAR16
*OutputString
;
760 Width
= (UINT16
) gOptionBlockWidth
;
764 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
765 if (StrLen (&OptionString
[Index
]) != 0) {
769 FreePool (OutputString
);
772 if ((Row
> MenuOption
->Skip
) &&
773 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
774 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
775 MenuOption
->Skip
= Row
;
780 Update display lines for a Menu Option.
782 @param MenuOption The MenuOption to be checked.
786 UpdateOptionSkipLines (
787 IN UI_MENU_OPTION
*MenuOption
790 CHAR16
*OptionString
;
794 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
795 if (OptionString
!= NULL
) {
796 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
798 FreePool (OptionString
);
801 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
802 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
804 if (OptionString
!= NULL
) {
805 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
807 FreePool (OptionString
);
813 Check whether this Menu Option could be highlighted.
815 This is an internal function.
817 @param MenuOption The MenuOption to be checked.
819 @retval TRUE This Menu Option is selectable.
820 @retval FALSE This Menu Option could not be selected.
825 UI_MENU_OPTION
*MenuOption
828 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
829 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
837 Move to next selectable statement.
839 This is an internal function.
841 @param GoUp The navigation direction. TRUE: up, FALSE: down.
842 @param CurrentPosition Current position.
843 @param GapToTop Gap position to top or bottom.
845 @return The row distance from current MenuOption to next selectable MenuOption.
847 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
848 @retval Value Find the selectable menu, maybe the truly selectable, maybe the l
849 last menu showing at current form.
853 MoveToNextStatement (
855 IN OUT LIST_ENTRY
**CurrentPosition
,
861 UI_MENU_OPTION
*NextMenuOption
;
862 UI_MENU_OPTION
*PreMenuOption
;
865 Pos
= *CurrentPosition
;
866 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
869 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
871 // NextMenuOption->Row == 0 means this menu has not calculate
872 // the NextMenuOption->Skip value yet, just calculate here.
874 if (NextMenuOption
->Row
== 0) {
875 UpdateOptionSkipLines (NextMenuOption
);
878 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
880 // In this case, still can't find the selectable menu,
881 // return the last one in the showing form.
883 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
884 NextMenuOption
= PreMenuOption
;
889 // Current Position doesn't need to be caculated when go up.
890 // Caculate distanct at first when go up
892 Distance
+= NextMenuOption
->Skip
;
895 if (IsSelectable (NextMenuOption
)) {
900 // Arrive at begin of the menu list.
902 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
909 // In this case, still can't find the selectable menu,
910 // return the last one in the showing form.
912 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
913 NextMenuOption
= PreMenuOption
;
917 Distance
+= NextMenuOption
->Skip
;
920 PreMenuOption
= NextMenuOption
;
921 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
924 *CurrentPosition
= &NextMenuOption
->Link
;
930 Process option string for date/time opcode.
932 @param MenuOption Menu option point to date/time.
933 @param OptionString Option string input for process.
934 @param AddOptCol Whether need to update MenuOption->OptCol.
938 ProcessStringForDateTime (
939 UI_MENU_OPTION
*MenuOption
,
940 CHAR16
*OptionString
,
946 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
950 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
952 Statement
= MenuOption
->ThisTag
;
955 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
956 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
957 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
958 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
962 // If leading spaces on OptionString - remove the spaces
964 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
966 // Base on the blockspace to get the option column info.
969 MenuOption
->OptCol
++;
973 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
974 OptionString
[Count
] = OptionString
[Index
];
977 OptionString
[Count
] = CHAR_NULL
;
980 // Enable to suppress field in the opcode base on the flag.
982 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
984 // OptionString format is: <**: **: ****>
988 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
990 // At this point, only "<**:" in the optionstring.
991 // Clean the day's ** field, after clean, the format is "< :"
993 SetUnicodeMem (&OptionString
[1], 2, L
' ');
994 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
996 // At this point, only "**:" in the optionstring.
997 // Clean the month's "**" field, after clean, the format is " :"
999 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1000 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1002 // At this point, only "****>" in the optionstring.
1003 // Clean the year's "****" field, after clean, the format is " >"
1005 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1007 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1009 // OptionString format is: <**: **: **>
1010 // |hour|minute|second|
1013 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1015 // At this point, only "<**:" in the optionstring.
1016 // Clean the hour's ** field, after clean, the format is "< :"
1018 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1019 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1021 // At this point, only "**:" in the optionstring.
1022 // Clean the minute's "**" field, after clean, the format is " :"
1024 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1025 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1027 // At this point, only "**>" in the optionstring.
1028 // Clean the second's "**" field, after clean, the format is " >"
1030 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1037 Adjust Data and Time position accordingly.
1038 Data format : [01/02/2004] [11:22:33]
1039 Line number : 0 0 1 0 0 1
1041 This is an internal function.
1043 @param DirectionUp the up or down direction. False is down. True is
1045 @param CurrentPosition Current position. On return: Point to the last
1046 Option (Year or Second) if up; Point to the first
1047 Option (Month or Hour) if down.
1049 @return Return line number to pad. It is possible that we stand on a zero-advance
1050 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1054 AdjustDateAndTimePosition (
1055 IN BOOLEAN DirectionUp
,
1056 IN OUT LIST_ENTRY
**CurrentPosition
1060 LIST_ENTRY
*NewPosition
;
1061 UI_MENU_OPTION
*MenuOption
;
1062 UINTN PadLineNumber
;
1065 NewPosition
= *CurrentPosition
;
1066 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1068 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1069 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1071 // Calculate the distance from current position to the last Date/Time MenuOption
1074 while (MenuOption
->Skip
== 0) {
1076 NewPosition
= NewPosition
->ForwardLink
;
1077 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1081 NewPosition
= *CurrentPosition
;
1084 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1085 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1086 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1087 // checking can be done.
1089 while (Count
++ < 2) {
1090 NewPosition
= NewPosition
->BackLink
;
1094 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1095 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1096 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1097 // checking can be done.
1099 while (Count
-- > 0) {
1100 NewPosition
= NewPosition
->ForwardLink
;
1104 *CurrentPosition
= NewPosition
;
1107 return PadLineNumber
;
1111 Get step info from numeric opcode.
1113 @param[in] OpCode The input numeric op code.
1115 @return step info for this opcode.
1119 IN EFI_IFR_OP_HEADER
*OpCode
1122 EFI_IFR_NUMERIC
*NumericOp
;
1125 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1127 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1128 case EFI_IFR_NUMERIC_SIZE_1
:
1129 Step
= NumericOp
->data
.u8
.Step
;
1132 case EFI_IFR_NUMERIC_SIZE_2
:
1133 Step
= NumericOp
->data
.u16
.Step
;
1136 case EFI_IFR_NUMERIC_SIZE_4
:
1137 Step
= NumericOp
->data
.u32
.Step
;
1140 case EFI_IFR_NUMERIC_SIZE_8
:
1141 Step
= NumericOp
->data
.u64
.Step
;
1153 Find the registered HotKey based on KeyData.
1155 @param[in] KeyData A pointer to a buffer that describes the keystroke
1156 information for the hot key.
1158 @return The registered HotKey context. If no found, NULL will return.
1161 GetHotKeyFromRegisterList (
1162 IN EFI_INPUT_KEY
*KeyData
1166 BROWSER_HOT_KEY
*HotKey
;
1168 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1169 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1170 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1172 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1176 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1184 Determine if the menu is the last menu that can be selected.
1186 This is an internal function.
1188 @param Direction The scroll direction. False is down. True is up.
1189 @param CurrentPos The current focus.
1191 @return FALSE -- the menu isn't the last menu that can be selected.
1192 @return TRUE -- the menu is the last menu that can be selected.
1197 IN BOOLEAN Direction
,
1198 IN LIST_ENTRY
*CurrentPos
1203 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1205 if (Temp
== &gMenuOption
) {
1213 Wait for a given event to fire, or for an optional timeout to expire.
1215 @param Event The event to wait for
1217 @retval UI_EVENT_TYPE The type of the event which is trigged.
1229 EFI_EVENT TimerEvent
;
1230 EFI_EVENT WaitList
[3];
1231 UI_EVENT_TYPE EventType
;
1234 Timeout
= FormExitTimeout(gFormData
);
1237 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1240 // Set the timer event
1249 WaitList
[0] = Event
;
1251 if (gFormData
->FormRefreshEvent
!= NULL
) {
1252 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1257 WaitList
[EventNum
] = TimerEvent
;
1261 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1262 ASSERT_EFI_ERROR (Status
);
1266 EventType
= UIEventKey
;
1270 if (gFormData
->FormRefreshEvent
!= NULL
) {
1271 EventType
= UIEventDriver
;
1273 ASSERT (Timeout
!= 0 && EventNum
== 2);
1274 EventType
= UIEventTimeOut
;
1279 ASSERT (Index
== 2 && EventNum
== 3);
1280 EventType
= UIEventTimeOut
;
1285 gBS
->CloseEvent (TimerEvent
);
1292 Get question id info from the input opcode header.
1294 @param OpCode The input opcode header pointer.
1296 @retval The question id for this opcode.
1301 IN EFI_IFR_OP_HEADER
*OpCode
1304 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1306 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1310 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1312 return QuestionHeader
->QuestionId
;
1316 Find the first menu which will be show at the top.
1318 @param FormData The data info for this form.
1319 @param TopOfScreen The link_entry pointer to top menu.
1320 @param HighlightMenu The menu which will be highlight.
1321 @param SkipValue The skip value for the top menu.
1326 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1327 OUT LIST_ENTRY
**TopOfScreen
,
1328 OUT LIST_ENTRY
**HighlightMenu
,
1337 UI_MENU_OPTION
*SavedMenuOption
;
1340 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1341 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1344 // If not has input highlight statement, just return the first one in this form.
1346 if (FormData
->HighLightedStatement
== NULL
) {
1347 *TopOfScreen
= gMenuOption
.ForwardLink
;
1348 *HighlightMenu
= gMenuOption
.ForwardLink
;
1349 if (!IsListEmpty (&gMenuOption
)) {
1350 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
);
1357 // Now base on the input highlight menu to find the top menu in this page.
1358 // Will base on the highlight menu show at the bottom to find the top menu.
1360 NewPos
= gMenuOption
.ForwardLink
;
1361 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1363 while ((SavedMenuOption
->ThisTag
!= FormData
->HighLightedStatement
) ||
1364 (SavedMenuOption
->Sequence
!= gSequence
)) {
1365 NewPos
= NewPos
->ForwardLink
;
1366 if (NewPos
== &gMenuOption
) {
1368 // Not Found it, break
1372 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1374 ASSERT (SavedMenuOption
->ThisTag
== FormData
->HighLightedStatement
);
1376 *HighlightMenu
= NewPos
;
1378 AdjustDateAndTimePosition(FALSE
, &NewPos
);
1379 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1380 UpdateOptionSkipLines (SavedMenuOption
);
1383 // If highlight opcode is date/time, keep the highlight row info not change.
1385 if ((SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) &&
1386 (gHighligthMenuInfo
.QuestionId
!= 0) &&
1387 (gHighligthMenuInfo
.QuestionId
== GetQuestionIdInfo(SavedMenuOption
->ThisTag
->OpCode
))) {
1389 // Still show the highlight menu before exit from display engine.
1391 EndRow
= gHighligthMenuInfo
.DisplayRow
+ SavedMenuOption
->Skip
;
1397 // Base on the selected menu will show at the bottome of next page,
1398 // select the menu show at the top of the next page.
1401 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= EndRow
; ) {
1402 Link
= Link
->BackLink
;
1404 // Already find the first menu in this form, means highlight menu
1405 // will show in first page of this form.
1407 if (Link
== &gMenuOption
) {
1408 *TopOfScreen
= gMenuOption
.ForwardLink
;
1412 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1413 UpdateOptionSkipLines (SavedMenuOption
);
1414 Index
+= SavedMenuOption
->Skip
;
1418 // Found the menu which will show at the top of the page.
1420 if (Link
== NewPos
) {
1422 // The menu can show more than one pages, just show the menu at the top of the page.
1425 *TopOfScreen
= Link
;
1428 // Check whether need to skip some line for menu shows at the top of the page.
1430 *SkipValue
= Index
- EndRow
;
1431 if (*SkipValue
> 0 && *SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
1432 *TopOfScreen
= Link
;
1435 *TopOfScreen
= Link
->ForwardLink
;
1441 Display menu and wait for user to select one menu option, then return it.
1442 If AutoBoot is enabled, then if user doesn't select any option,
1443 after period of time, it will automatically return the first menu option.
1445 @param FormData The current form data info.
1447 @retval EFI_SUCESSS Process the user selection success.
1448 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
1453 IN FORM_DISPLAY_ENGINE_FORM
*FormData
1458 UINTN DistanceValue
;
1471 CHAR16
*OptionString
;
1472 CHAR16
*OutputString
;
1474 CHAR16
*HelpHeaderString
;
1475 CHAR16
*HelpBottomString
;
1484 LIST_ENTRY
*TopOfScreen
;
1485 LIST_ENTRY
*SavedListEntry
;
1486 UI_MENU_OPTION
*MenuOption
;
1487 UI_MENU_OPTION
*NextMenuOption
;
1488 UI_MENU_OPTION
*SavedMenuOption
;
1489 UI_MENU_OPTION
*PreviousMenuOption
;
1490 UI_CONTROL_FLAG ControlFlag
;
1491 UI_SCREEN_OPERATION ScreenOperation
;
1493 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1494 UINTN ModalSkipColumn
;
1495 BROWSER_HOT_KEY
*HotKey
;
1496 UINTN HelpPageIndex
;
1497 UINTN HelpPageCount
;
1500 UINTN HelpHeaderLine
;
1501 UINTN HelpBottomLine
;
1502 BOOLEAN MultiHelpPage
;
1504 UINT16 EachLineWidth
;
1505 UINT16 HeaderLineWidth
;
1506 UINT16 BottomLineWidth
;
1507 EFI_STRING_ID HelpInfo
;
1508 UI_EVENT_TYPE EventType
;
1509 FORM_DISPLAY_ENGINE_STATEMENT
*InitialHighlight
;
1511 EventType
= UIEventNone
;
1512 Status
= EFI_SUCCESS
;
1514 HelpHeaderString
= NULL
;
1515 HelpBottomString
= NULL
;
1516 OptionString
= NULL
;
1517 ScreenOperation
= UiNoOperation
;
1526 MultiHelpPage
= FALSE
;
1528 HeaderLineWidth
= 0;
1529 BottomLineWidth
= 0;
1530 OutputString
= NULL
;
1535 NextMenuOption
= NULL
;
1536 PreviousMenuOption
= NULL
;
1537 SavedMenuOption
= NULL
;
1541 ModalSkipColumn
= (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
1542 InitialHighlight
= gFormData
->HighLightedStatement
;
1544 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1546 gOptionBlockWidth
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3);
1547 gPromptBlockWidth
= (CHAR16
) (gOptionBlockWidth
+ LEFT_SKIPPED_COLUMNS
);
1548 gHelpBlockWidth
= (CHAR16
) (gOptionBlockWidth
- LEFT_SKIPPED_COLUMNS
);
1550 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1551 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
1554 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1555 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1557 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1560 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
1562 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1564 ControlFlag
= CfInitialization
;
1566 switch (ControlFlag
) {
1567 case CfInitialization
:
1568 if (IsListEmpty (&gMenuOption
)) {
1570 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) == 0) {
1572 // Clear Statement range.
1575 gStatementDimensions
.LeftColumn
,
1576 gStatementDimensions
.RightColumn
,
1577 TopRow
- SCROLL_ARROW_HEIGHT
,
1578 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1579 GetFieldTextColor ()
1585 RefreshKeyHelp (gFormData
, NULL
, FALSE
);
1588 ControlFlag
= CfReadKey
;
1590 ControlFlag
= CfRepaint
;
1595 ControlFlag
= CfRefreshHighLight
;
1605 Temp
= (UINTN
) SkipValue
;
1606 Temp2
= (UINTN
) SkipValue
;
1607 Temp3
= (UINTN
) SkipValue
;
1610 // 1. Clear the screen.
1612 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1614 gStatementDimensions
.LeftColumn
+ ModalSkipColumn
,
1615 gStatementDimensions
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1616 TopRow
- SCROLL_ARROW_HEIGHT
,
1617 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1618 GetFieldTextColor ()
1621 TempRightCol
= gStatementDimensions
.RightColumn
;
1622 if (!mStatementLayoutIsChanged
) {
1623 TempRightCol
= gStatementDimensions
.RightColumn
- gHelpBlockWidth
;
1626 gStatementDimensions
.LeftColumn
,
1627 gStatementDimensions
.RightColumn
,
1628 TopRow
- SCROLL_ARROW_HEIGHT
,
1630 GetFieldTextColor ()
1633 gStatementDimensions
.LeftColumn
,
1637 GetFieldTextColor ()
1640 gStatementDimensions
.LeftColumn
,
1641 gStatementDimensions
.RightColumn
,
1643 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1644 GetFieldTextColor ()
1649 // 2.Paint the menu.
1651 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1652 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1653 MenuOption
->Row
= Row
;
1654 MenuOption
->Col
= Col
;
1655 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1656 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + gStatementDimensions
.LeftColumn
+ ModalSkipColumn
;
1658 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + gStatementDimensions
.LeftColumn
;
1661 Statement
= MenuOption
->ThisTag
;
1662 if (MenuOption
->NestInStatement
) {
1663 MenuOption
->Col
+= SUBTITLE_INDENT
;
1666 if (MenuOption
->GrayOut
) {
1667 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1669 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1670 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1674 Width
= GetWidth (Statement
);
1678 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1680 // Print Arrow for Goto button.
1683 MenuOption
->Col
- 2,
1685 GEOMETRICSHAPE_RIGHT_TRIANGLE
1690 // 2.1. Paint the description.
1692 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1694 // Temp means need to skip how many lines from the start.
1696 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1697 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1700 // If there is more string to process print on the next row and increment the Skip value
1702 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1708 FreePool (OutputString
);
1718 // 2.2. Paint the option string.
1720 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
1722 // If Error occur, question value update in ProcessOptions.
1723 // Exit current FormDisplay with new question value.
1725 if (EFI_ERROR (Status
)) {
1729 if (OptionString
!= NULL
) {
1730 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1731 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
1734 Width
= (UINT16
) gOptionBlockWidth
;
1738 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1739 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
1740 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1743 // If there is more string to process print on the next row and increment the Skip value
1745 if (StrLen (&OptionString
[Index
]) != 0) {
1749 // Since the Number of lines for this menu entry may or may not be reflected accurately
1750 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1751 // some testing to ensure we are keeping this in-sync.
1753 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1755 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1761 FreePool (OutputString
);
1769 FreePool (OptionString
);
1774 // If this is a text op with secondary text information
1776 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1777 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1779 Width
= (UINT16
) gOptionBlockWidth
;
1783 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1784 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
1785 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
1788 // If there is more string to process print on the next row and increment the Skip value
1790 if (StrLen (&StringPtr
[Index
]) != 0) {
1794 // Since the Number of lines for this menu entry may or may not be reflected accurately
1795 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1796 // some testing to ensure we are keeping this in-sync.
1798 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1800 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1806 FreePool (OutputString
);
1813 FreePool (StringPtr
);
1817 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1820 // 3. Update the row info which will be used by next menu.
1822 if (Link
== TopOfScreen
) {
1823 Row
+= MenuOption
->Skip
- SkipValue
;
1825 Row
+= MenuOption
->Skip
;
1828 if (Row
> BottomRow
) {
1829 if (!ValueIsScroll (FALSE
, Link
)) {
1833 Row
= BottomRow
+ 1;
1838 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
1843 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
1845 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1846 TopRow
- SCROLL_ARROW_HEIGHT
,
1849 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1853 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
1855 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
1856 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1859 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1866 case CfRefreshHighLight
:
1869 // MenuOption: Last menu option that need to remove hilight
1870 // MenuOption is set to NULL in Repaint
1871 // NewPos: Current menu option that need to hilight
1873 ControlFlag
= CfUpdateHelpString
;
1875 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
1880 if (NewPos
== TopOfScreen
) {
1886 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
1887 if (MenuOption
!= NULL
) {
1889 // Remove highlight on last Menu Option
1891 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1892 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
1893 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1894 if (OptionString
!= NULL
) {
1895 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1896 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
1898 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
1901 Width
= (UINT16
) gOptionBlockWidth
;
1902 OriginalRow
= MenuOption
->Row
;
1905 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1906 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
1907 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
1910 // If there is more string to process print on the next row and increment the Skip value
1912 if (StrLen (&OptionString
[Index
]) != 0) {
1918 FreePool (OutputString
);
1924 MenuOption
->Row
= OriginalRow
;
1926 FreePool (OptionString
);
1929 if (MenuOption
->GrayOut
) {
1930 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1931 } else if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1932 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1935 OriginalRow
= MenuOption
->Row
;
1936 Width
= GetWidth (MenuOption
->ThisTag
);
1939 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1940 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
1941 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
1944 // If there is more string to process print on the next row and increment the Skip value
1946 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1952 FreePool (OutputString
);
1958 MenuOption
->Row
= OriginalRow
;
1959 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1965 // This is the current selected statement
1967 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1968 Statement
= MenuOption
->ThisTag
;
1971 // Get the highlight statement.
1973 gUserInput
->SelectedStatement
= Statement
;
1974 gSequence
= (UINT16
) MenuOption
->Sequence
;
1977 // Record highlight row info for date/time opcode.
1979 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1980 gHighligthMenuInfo
.QuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1981 gHighligthMenuInfo
.DisplayRow
= (UINT16
) MenuOption
->Row
;
1983 gHighligthMenuInfo
.QuestionId
= 0;
1984 gHighligthMenuInfo
.DisplayRow
= 0;
1987 if (!IsSelectable (MenuOption
)) {
1988 RefreshKeyHelp(gFormData
, Statement
, FALSE
);
1993 // Set reverse attribute
1995 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1996 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
1998 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
1999 if (OptionString
!= NULL
) {
2000 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2001 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2003 Width
= (UINT16
) gOptionBlockWidth
;
2005 OriginalRow
= MenuOption
->Row
;
2008 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2009 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2010 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2013 // If there is more string to process print on the next row and increment the Skip value
2015 if (StrLen (&OptionString
[Index
]) != 0) {
2021 FreePool (OutputString
);
2027 MenuOption
->Row
= OriginalRow
;
2029 FreePool (OptionString
);
2032 OriginalRow
= MenuOption
->Row
;
2034 Width
= GetWidth (Statement
);
2037 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2038 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2039 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2042 // If there is more string to process print on the next row and increment the Skip value
2044 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2050 FreePool (OutputString
);
2056 MenuOption
->Row
= OriginalRow
;
2061 RefreshKeyHelp(gFormData
, MenuOption
->ThisTag
, FALSE
);
2064 // Clear reverse attribute
2066 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2070 case CfUpdateHelpString
:
2071 ControlFlag
= CfPrepareToReadKey
;
2072 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2076 if (Repaint
|| NewLine
) {
2078 // Don't print anything if it is a NULL help token
2080 ASSERT(MenuOption
!= NULL
);
2081 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2082 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2083 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2085 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2088 RowCount
= BottomRow
- TopRow
+ 1;
2091 // 1.Calculate how many line the help string need to print.
2093 if (HelpString
!= NULL
) {
2094 FreePool (HelpString
);
2097 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2098 FreePool (StringPtr
);
2100 if (HelpLine
> RowCount
) {
2101 MultiHelpPage
= TRUE
;
2102 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2103 if (HelpHeaderString
!= NULL
) {
2104 FreePool (HelpHeaderString
);
2105 HelpHeaderString
= NULL
;
2107 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2108 FreePool (StringPtr
);
2109 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2110 if (HelpBottomString
!= NULL
) {
2111 FreePool (HelpBottomString
);
2112 HelpBottomString
= NULL
;
2114 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2115 FreePool (StringPtr
);
2117 // Calculate the help page count.
2119 if (HelpLine
> 2 * RowCount
- 2) {
2120 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2121 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
2128 MultiHelpPage
= FALSE
;
2133 // Check whether need to show the 'More(U/u)' at the begin.
2134 // Base on current direct info, here shows aligned to the right side of the column.
2135 // If the direction is multi line and aligned to right side may have problem, so
2136 // add ASSERT code here.
2138 if (HelpPageIndex
> 0) {
2139 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2140 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2141 ASSERT (HelpHeaderLine
== 1);
2142 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2143 PrintStringAtWithWidth (
2144 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2150 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2152 &HelpHeaderString
[Index
* HeaderLineWidth
]
2157 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
2159 // Print the help string info.
2161 if (!MultiHelpPage
) {
2162 for (Index
= 0; Index
< HelpLine
; Index
++) {
2163 PrintStringAtWithWidth (
2164 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2166 &HelpString
[Index
* EachLineWidth
],
2170 for (; Index
< RowCount
; Index
++) {
2171 PrintStringAtWithWidth (
2172 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2178 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2180 if (HelpPageIndex
== 0) {
2181 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
2182 PrintStringAtWithWidth (
2183 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2185 &HelpString
[Index
* EachLineWidth
],
2190 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
2191 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
2192 PrintStringAtWithWidth (
2193 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2194 Index
+ TopRow
+ HelpHeaderLine
,
2195 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
2199 if (HelpPageIndex
== HelpPageCount
- 1) {
2200 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
2201 PrintStringAtWithWidth (
2202 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2203 Index
+ TopRow
+ HelpHeaderLine
,
2208 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2214 // Check whether need to print the 'More(D/d)' at the bottom.
2215 // Base on current direct info, here shows aligned to the right side of the column.
2216 // If the direction is multi line and aligned to right side may have problem, so
2217 // add ASSERT code here.
2219 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
2220 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2221 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
2222 ASSERT (HelpBottomLine
== 1);
2223 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2224 PrintStringAtWithWidth (
2225 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2226 BottomRow
+ Index
- HelpBottomLine
+ 1,
2231 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
2232 BottomRow
+ Index
- HelpBottomLine
+ 1,
2233 &HelpBottomString
[Index
* BottomLineWidth
]
2238 // Reset this flag every time we finish using it.
2244 case CfPrepareToReadKey
:
2245 ControlFlag
= CfReadKey
;
2246 ScreenOperation
= UiNoOperation
;
2250 ControlFlag
= CfScreenOperation
;
2253 // Wait for user's selection
2256 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2257 if (!EFI_ERROR (Status
)) {
2258 EventType
= UIEventKey
;
2263 // If we encounter error, continue to read another key in.
2265 if (Status
!= EFI_NOT_READY
) {
2269 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
2270 if (EventType
== UIEventKey
) {
2271 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2276 if (EventType
== UIEventDriver
) {
2277 gUserInput
->Action
= BROWSER_ACTION_NONE
;
2278 ControlFlag
= CfExit
;
2282 if (EventType
== UIEventTimeOut
) {
2283 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2284 ControlFlag
= CfExit
;
2288 switch (Key
.UnicodeChar
) {
2289 case CHAR_CARRIAGE_RETURN
:
2290 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2291 ControlFlag
= CfReadKey
;
2295 ScreenOperation
= UiSelect
;
2300 // We will push the adjustment of these numeric values directly to the input handler
2301 // NOTE: we won't handle manual input numeric
2306 // If the screen has no menu items, and the user didn't select UiReset
2307 // ignore the selection and go back to reading keys.
2309 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2310 ControlFlag
= CfReadKey
;
2314 ASSERT(MenuOption
!= NULL
);
2315 Statement
= MenuOption
->ThisTag
;
2316 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
2317 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2318 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
2320 if (Key
.UnicodeChar
== '+') {
2321 gDirection
= SCAN_RIGHT
;
2323 gDirection
= SCAN_LEFT
;
2326 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2327 if (OptionString
!= NULL
) {
2328 FreePool (OptionString
);
2330 if (EFI_ERROR (Status
)) {
2332 // Repaint to clear possible error prompt pop-up
2337 ControlFlag
= CfExit
;
2343 ScreenOperation
= UiUp
;
2348 ScreenOperation
= UiDown
;
2352 if(IsListEmpty (&gMenuOption
)) {
2353 ControlFlag
= CfReadKey
;
2357 ASSERT(MenuOption
!= NULL
);
2358 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
2359 ScreenOperation
= UiSelect
;
2365 if (!MultiHelpPage
) {
2366 ControlFlag
= CfReadKey
;
2369 ControlFlag
= CfUpdateHelpString
;
2370 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
2375 if (!MultiHelpPage
) {
2376 ControlFlag
= CfReadKey
;
2379 ControlFlag
= CfUpdateHelpString
;
2380 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
2384 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2385 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2386 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2391 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2393 // ModalForm has no ESC key and Hot Key.
2395 ControlFlag
= CfReadKey
;
2396 } else if (Index
== mScanCodeNumber
) {
2398 // Check whether Key matches the registered hot key.
2401 HotKey
= GetHotKeyFromRegisterList (&Key
);
2402 if (HotKey
!= NULL
) {
2403 ScreenOperation
= UiHotKey
;
2410 case CfScreenOperation
:
2411 if (ScreenOperation
!= UiReset
) {
2413 // If the screen has no menu items, and the user didn't select UiReset
2414 // ignore the selection and go back to reading keys.
2416 if (IsListEmpty (&gMenuOption
)) {
2417 ControlFlag
= CfReadKey
;
2423 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2426 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2427 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2434 ControlFlag
= CfRepaint
;
2436 ASSERT(MenuOption
!= NULL
);
2437 Statement
= MenuOption
->ThisTag
;
2438 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2442 switch (Statement
->OpCode
->OpCode
) {
2443 case EFI_IFR_REF_OP
:
2444 case EFI_IFR_ACTION_OP
:
2445 case EFI_IFR_RESET_BUTTON_OP
:
2446 ControlFlag
= CfExit
;
2451 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2453 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
2454 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2456 if (OptionString
!= NULL
) {
2457 FreePool (OptionString
);
2460 if (EFI_ERROR (Status
)) {
2463 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
2466 ControlFlag
= CfExit
;
2474 // We come here when someone press ESC
2475 // If the policy is not exit front page when user press ESC, process here.
2477 if (!FormExitPolicy()) {
2480 ControlFlag
= CfRepaint
;
2485 // When user press ESC, it will try to show another menu, should clean the gSequence info.
2487 if (gSequence
!= 0) {
2491 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2492 ControlFlag
= CfExit
;
2496 ControlFlag
= CfRepaint
;
2498 gUserInput
->Action
= HotKey
->Action
;
2499 ControlFlag
= CfExit
;
2503 ControlFlag
= CfRepaint
;
2504 ASSERT(MenuOption
!= NULL
);
2505 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2506 if (MenuOption
->Sequence
!= 0) {
2508 // In the middle or tail of the Date/Time op-code set, go left.
2510 ASSERT(NewPos
!= NULL
);
2511 NewPos
= NewPos
->BackLink
;
2517 ControlFlag
= CfRepaint
;
2518 ASSERT(MenuOption
!= NULL
);
2519 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2520 if (MenuOption
->Sequence
!= 2) {
2522 // In the middle or tail of the Date/Time op-code set, go left.
2524 ASSERT(NewPos
!= NULL
);
2525 NewPos
= NewPos
->ForwardLink
;
2531 ControlFlag
= CfRepaint
;
2533 SavedListEntry
= NewPos
;
2535 ASSERT(NewPos
!= NULL
);
2537 // Adjust Date/Time position before we advance forward.
2539 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2540 if (NewPos
->BackLink
!= &gMenuOption
) {
2541 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2542 ASSERT (MenuOption
!= NULL
);
2544 NewPos
= NewPos
->BackLink
;
2546 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2547 if (PreviousMenuOption
->Row
== 0) {
2548 UpdateOptionSkipLines (PreviousMenuOption
);
2550 DistanceValue
= PreviousMenuOption
->Skip
;
2552 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2553 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2555 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2557 if (Difference
< 0) {
2559 // We hit the begining MenuOption that can be focused
2560 // so we simply scroll to the top.
2562 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2563 TopOfScreen
= gMenuOption
.ForwardLink
;
2567 // Scroll up to the last page when we have arrived at top page.
2569 NewPos
= &gMenuOption
;
2570 TopOfScreen
= &gMenuOption
;
2571 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2572 ScreenOperation
= UiPageUp
;
2573 ControlFlag
= CfScreenOperation
;
2576 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2578 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2580 TopOfScreen
= NewPos
;
2583 } else if (!IsSelectable (NextMenuOption
)) {
2585 // Continue to go up until scroll to next page or the selectable option is found.
2587 ScreenOperation
= UiUp
;
2588 ControlFlag
= CfScreenOperation
;
2592 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2594 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2595 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2596 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2597 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2600 // Scroll up to the last page.
2602 NewPos
= &gMenuOption
;
2603 TopOfScreen
= &gMenuOption
;
2604 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2605 ScreenOperation
= UiPageUp
;
2606 ControlFlag
= CfScreenOperation
;
2612 // SkipValue means lines is skipped when show the top menu option.
2614 ControlFlag
= CfRepaint
;
2616 ASSERT(NewPos
!= NULL
);
2618 // Already at the first menu option, Check the skip value.
2620 if (NewPos
->BackLink
== &gMenuOption
) {
2621 if (SkipValue
== 0) {
2636 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
2637 // form of options to be show, so just update the SkipValue to show the next
2638 // parts of options.
2640 if (SkipValue
> (INTN
) (BottomRow
- TopRow
+ 1)) {
2641 SkipValue
-= BottomRow
- TopRow
+ 1;
2647 // First minus the menu of the top screen, it's value is SkipValue.
2649 Index
= (BottomRow
+ 1) - SkipValue
;
2650 while ((Index
> TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2651 Link
= Link
->BackLink
;
2652 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2653 if (PreviousMenuOption
->Row
== 0) {
2654 UpdateOptionSkipLines (PreviousMenuOption
);
2656 if (Index
< PreviousMenuOption
->Skip
) {
2659 Index
= Index
- PreviousMenuOption
->Skip
;
2662 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2664 if (TopOfScreen
== &gMenuOption
) {
2665 TopOfScreen
= gMenuOption
.ForwardLink
;
2666 NewPos
= gMenuOption
.BackLink
;
2667 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2669 } else if (TopOfScreen
!= Link
) {
2672 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2675 // Finally we know that NewPos is the last MenuOption can be focused.
2679 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2682 if (Index
> TopRow
) {
2684 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
2686 SkipValue
= PreviousMenuOption
->Skip
- (Index
- TopRow
);
2687 } else if (Index
== TopRow
) {
2690 SkipValue
= TopRow
- Index
;
2694 // Move to the option in Next page.
2696 if (TopOfScreen
== &gMenuOption
) {
2697 NewPos
= gMenuOption
.BackLink
;
2698 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2701 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2705 // There are more MenuOption needing scrolling up.
2712 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2713 // Don't do this when we are already in the first page.
2715 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2716 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2721 // SkipValue means lines is skipped when show the top menu option.
2723 ControlFlag
= CfRepaint
;
2725 ASSERT (NewPos
!= NULL
);
2726 if (NewPos
->ForwardLink
== &gMenuOption
) {
2735 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2736 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
2738 // Count to the menu option which will show at the top of the next form.
2740 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
2741 Link
= Link
->ForwardLink
;
2742 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2743 Index
= Index
+ NextMenuOption
->Skip
;
2746 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
2748 // Finally we know that NewPos is the last MenuOption can be focused.
2751 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2754 // Calculate the skip line for top of screen menu.
2756 if (Link
== TopOfScreen
) {
2758 // The top of screen menu option occupies the entire form.
2760 SkipValue
+= BottomRow
- TopRow
+ 1;
2762 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
2768 // Move to the Next selectable menu.
2770 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
2774 // Save the menu as the next highlight menu.
2779 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2780 // Don't do this when we are already in the last page.
2782 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2783 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2788 // SkipValue means lines is skipped when show the top menu option.
2789 // NewPos points to the menu which is highlighted now.
2791 ControlFlag
= CfRepaint
;
2794 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
2795 // to be one that progresses to the next set of op-codes, we need to advance to the last
2796 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
2797 // checking can be done. The only other logic we need to introduce is that if a Date/Time
2798 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
2799 // the Date/Time op-code.
2801 SavedListEntry
= NewPos
;
2802 AdjustDateAndTimePosition (FALSE
, &NewPos
);
2804 if (NewPos
->ForwardLink
!= &gMenuOption
) {
2805 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2807 NewPos
= NewPos
->ForwardLink
;
2811 // Current menu not at the bottom of the form.
2813 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
2815 // Find the next selectable menu.
2817 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
2819 // We hit the end of MenuOption that can be focused
2820 // so we simply scroll to the first page.
2822 if (Difference
< 0) {
2824 // Scroll to the first page.
2826 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2827 TopOfScreen
= gMenuOption
.ForwardLink
;
2831 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2833 NewPos
= gMenuOption
.ForwardLink
;
2834 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2838 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2840 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2841 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2845 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2846 if (NextMenuOption
->Row
== 0) {
2847 UpdateOptionSkipLines (NextMenuOption
);
2849 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
2851 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
2852 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
2853 (NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
||
2854 NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2860 // If we are going to scroll, update TopOfScreen
2862 if (Temp
> BottomRow
) {
2865 // Is the current top of screen a zero-advance op-code?
2866 // If so, keep moving forward till we hit a >0 advance op-code
2868 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2871 // If bottom op-code is more than one line or top op-code is more than one line
2873 if ((DistanceValue
> 1) || (SavedMenuOption
->Skip
> 1)) {
2875 // Is the bottom op-code greater than or equal in size to the top op-code?
2877 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
2879 // Skip the top op-code
2881 TopOfScreen
= TopOfScreen
->ForwardLink
;
2882 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
2884 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2887 // If we have a remainder, skip that many more op-codes until we drain the remainder
2889 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
2891 // Since the Difference is greater than or equal to this op-code's skip value, skip it
2893 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
2894 TopOfScreen
= TopOfScreen
->ForwardLink
;
2895 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
2898 // Since we will act on this op-code in the next routine, and increment the
2899 // SkipValue, set the skips to one less than what is required.
2901 SkipValue
= Difference
- 1;
2904 // Since we will act on this op-code in the next routine, and increment the
2905 // SkipValue, set the skips to one less than what is required.
2907 SkipValue
+= (Temp
- BottomRow
) - 1;
2910 if ((SkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
2911 TopOfScreen
= TopOfScreen
->ForwardLink
;
2916 // If the op-code at the top of the screen is more than one line, let's not skip it yet
2917 // Let's set a skip flag to smoothly scroll the top of the screen.
2919 if (SavedMenuOption
->Skip
> 1) {
2920 if (SavedMenuOption
== NextMenuOption
) {
2925 } else if (SavedMenuOption
->Skip
== 1) {
2929 TopOfScreen
= TopOfScreen
->ForwardLink
;
2931 } while (SavedMenuOption
->Skip
== 0);
2934 } else if (!IsSelectable (NextMenuOption
)) {
2936 // Continue to go down until scroll to next page or the selectable option is found.
2938 ScreenOperation
= UiDown
;
2939 ControlFlag
= CfScreenOperation
;
2942 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2944 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2948 // Scroll to the first page.
2950 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2951 TopOfScreen
= gMenuOption
.ForwardLink
;
2956 // Need to remove the current highlight menu.
2957 // MenuOption saved the last highlight menu info.
2959 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2965 // Get the next highlight menu.
2967 NewPos
= gMenuOption
.ForwardLink
;
2968 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2972 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
2974 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2975 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2978 case CfUiNoOperation
:
2979 ControlFlag
= CfRepaint
;
2983 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
2984 if (HelpString
!= NULL
) {
2985 FreePool (HelpString
);
2987 if (HelpHeaderString
!= NULL
) {
2988 FreePool (HelpHeaderString
);
2990 if (HelpBottomString
!= NULL
) {
2991 FreePool (HelpBottomString
);
3003 Base on the browser status info to show an pop up message.
3007 BrowserStatusProcess (
3014 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3018 if (gFormData
->ErrorString
!= NULL
) {
3019 ErrorInfo
= gFormData
->ErrorString
;
3021 switch (gFormData
->BrowserStatus
) {
3022 case BROWSER_SUBMIT_FAIL
:
3023 ErrorInfo
= gSaveFailed
;
3026 case BROWSER_NO_SUBMIT_IF
:
3027 ErrorInfo
= gNoSubmitIf
;
3030 case BROWSER_FORM_NOT_FOUND
:
3031 ErrorInfo
= gFormNotFound
;
3034 case BROWSER_FORM_SUPPRESS
:
3035 ErrorInfo
= gFormSuppress
;
3038 case BROWSER_PROTOCOL_NOT_FOUND
:
3039 ErrorInfo
= gProtocolNotFound
;
3043 ErrorInfo
= gBrwoserError
;
3049 // Error occur, prompt error message.
3052 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3053 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3057 Display one form, and return user input.
3059 @param FormData Form Data to be shown.
3060 @param UserInputData User input data.
3062 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
3063 2.Error info has show and return.
3064 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
3065 @retval EFI_NOT_FOUND New form data has some error.
3070 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
3071 OUT USER_INPUT
*UserInputData
3076 ASSERT (FormData
!= NULL
);
3077 if (FormData
== NULL
) {
3078 return EFI_INVALID_PARAMETER
;
3081 gUserInput
= UserInputData
;
3082 gFormData
= FormData
;
3085 // Process the status info first.
3087 BrowserStatusProcess();
3088 if (UserInputData
== NULL
) {
3090 // UserInputData == NULL, means only need to print the error info, return here.
3095 ConvertStatementToMenu();
3097 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
3098 if (EFI_ERROR (Status
)) {
3103 // Check whether layout is changed.
3106 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
3107 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
3108 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
3109 mStatementLayoutIsChanged
= TRUE
;
3111 mStatementLayoutIsChanged
= FALSE
;
3114 Status
= UiDisplayMenu(FormData
);
3117 // Backup last form info.
3119 mIsFirstForm
= FALSE
;
3120 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
3121 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
3122 gOldFormEntry
.FormId
= FormData
->FormId
;
3128 Clear Screen to the initial state.
3132 DriverClearDisplayPage (
3136 ClearDisplayPage ();
3137 mIsFirstForm
= TRUE
;
3141 Set Buffer to Value for Size bytes.
3143 @param Buffer Memory to set.
3144 @param Size Number of bytes to set
3145 @param Value Value of the set operation.
3158 while ((Size
--) != 0) {
3164 Initialize Setup Browser driver.
3166 @param ImageHandle The image handle.
3167 @param SystemTable The system table.
3169 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
3170 @return Other value if failed to initialize the Setup Browser module.
3175 InitializeDisplayEngine (
3176 IN EFI_HANDLE ImageHandle
,
3177 IN EFI_SYSTEM_TABLE
*SystemTable
3181 EFI_INPUT_KEY HotKey
;
3182 EFI_STRING NewString
;
3183 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
3186 // Publish our HII data
3188 gHiiHandle
= HiiAddPackages (
3189 &gDisplayEngineGuid
,
3191 DisplayEngineStrings
,
3194 ASSERT (gHiiHandle
!= NULL
);
3197 // Install Form Display protocol
3199 Status
= gBS
->InstallProtocolInterface (
3200 &mPrivateData
.Handle
,
3201 &gEdkiiFormDisplayEngineProtocolGuid
,
3202 EFI_NATIVE_INTERFACE
,
3203 &mPrivateData
.FromDisplayProt
3205 ASSERT_EFI_ERROR (Status
);
3207 InitializeDisplayStrings();
3209 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
3210 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
3213 // Use BrowserEx2 protocol to register HotKey.
3215 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
3216 if (!EFI_ERROR (Status
)) {
3218 // Register the default HotKey F9 and F10 again.
3220 HotKey
.UnicodeChar
= CHAR_NULL
;
3221 HotKey
.ScanCode
= SCAN_F10
;
3222 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
3223 ASSERT (NewString
!= NULL
);
3224 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
3226 HotKey
.ScanCode
= SCAN_F9
;
3227 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
3228 ASSERT (NewString
!= NULL
);
3229 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
3236 This is the default unload handle for display core drivers.
3238 @param[in] ImageHandle The drivers' driver image.
3240 @retval EFI_SUCCESS The image is unloaded.
3241 @retval Others Failed to unload the image.
3246 UnloadDisplayEngine (
3247 IN EFI_HANDLE ImageHandle
3250 HiiRemovePackages(gHiiHandle
);
3252 FreeDisplayStrings ();