2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 Some presentation routines.
39 // For now, allocate an arbitrarily long buffer
41 Buffer
= AllocateZeroPool (0x10000);
42 ASSERT (Buffer
!= NULL
);
45 // Set foreground and background as defined
47 gST
->ConOut
->SetAttribute (gST
->ConOut
, TextAttribute
);
50 // Much faster to buffer the long string instead of print it a character at a time
52 SetUnicodeMem (Buffer
, RightColumn
- LeftColumn
, L
' ');
55 // Clear the desired area with the appropriate foreground/background
57 for (Row
= TopRow
; Row
<= BottomRow
; Row
++) {
58 PrintStringAt (LeftColumn
, Row
, Buffer
);
61 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, LeftColumn
, TopRow
);
63 gBS
->FreePool (Buffer
);
75 for (Length
= 0; Destination
[Length
] != 0; Length
++)
79 // We now have the length of the original string
80 // We can safely assume for now that we are concatenating a narrow value to this string.
81 // For instance, the string is "XYZ" and cat'ing ">"
82 // If this assumption changes, we need to make this routine a bit more complex
84 Destination
[Length
] = (CHAR16
) NARROW_CHAR
;
87 StrCpy (Destination
+ Length
, Source
);
105 // Advance to the null-terminator or to the first width directive
108 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
109 Index
++, Count
= Count
+ IncrementValue
114 // We hit the null-terminator, we now have a count
116 if (String
[Index
] == 0) {
120 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
121 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
123 if (String
[Index
] == NARROW_CHAR
) {
125 // Skip to the next character
131 // Skip to the next character
136 } while (String
[Index
] != 0);
139 // Increment by one to include the null-terminator in the size
143 return Count
* sizeof (CHAR16
);
156 CHAR16
*StrFrontPageBanner
;
157 EFI_SCREEN_DESCRIPTOR LocalScreen
;
160 ZeroMem (&LocalScreen
, sizeof (EFI_SCREEN_DESCRIPTOR
));
161 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &LocalScreen
.RightColumn
, &LocalScreen
.BottomRow
);
162 ClearLines (0, LocalScreen
.RightColumn
, 0, LocalScreen
.BottomRow
, KEYHELP_BACKGROUND
);
164 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
167 // For now, allocate an arbitrarily long buffer
169 Buffer
= AllocateZeroPool (0x10000);
170 ASSERT (Buffer
!= NULL
);
172 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
174 for (Index
= 0; Index
+ 2 < (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
); Index
++) {
175 Buffer
[Index
] = Character
;
178 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
180 // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
183 LocalScreen
.LeftColumn
,
184 LocalScreen
.RightColumn
,
186 FRONT_PAGE_HEADER_HEIGHT
- 1 + LocalScreen
.TopRow
,
187 BANNER_TEXT
| BANNER_BACKGROUND
190 // for (Line = 0; Line < BANNER_HEIGHT; Line++) {
192 for (Line
= (UINT8
) LocalScreen
.TopRow
; Line
< BANNER_HEIGHT
+ (UINT8
) LocalScreen
.TopRow
; Line
++) {
194 // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
196 for (Alignment
= (UINT8
) LocalScreen
.LeftColumn
;
197 Alignment
< BANNER_COLUMNS
+ (UINT8
) LocalScreen
.LeftColumn
;
200 if (BannerData
->Banner
[Line
- (UINT8
) LocalScreen
.TopRow
][Alignment
- (UINT8
) LocalScreen
.LeftColumn
] != 0x0000) {
201 StrFrontPageBanner
= GetToken (
202 BannerData
->Banner
[Line
- (UINT8
) LocalScreen
.TopRow
][Alignment
- (UINT8
) LocalScreen
.LeftColumn
],
209 switch (Alignment
- LocalScreen
.LeftColumn
) {
212 // Handle left column
214 PrintStringAt (LocalScreen
.LeftColumn
, Line
, StrFrontPageBanner
);
219 // Handle center column
222 LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 3,
230 // Handle right column
233 LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) * 2 / 3,
240 gBS
->FreePool (StrFrontPageBanner
);
246 LocalScreen
.LeftColumn
,
247 LocalScreen
.RightColumn
,
248 LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
,
249 LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- 1,
250 KEYHELP_TEXT
| KEYHELP_BACKGROUND
253 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
255 LocalScreen
.LeftColumn
,
256 LocalScreen
.RightColumn
,
258 LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
- 1,
259 TITLE_TEXT
| TITLE_BACKGROUND
262 // Print Top border line
263 // +------------------------------------------------------------------------------+
265 // +------------------------------------------------------------------------------+
267 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
269 PrintChar (Character
);
270 PrintString (Buffer
);
272 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
273 PrintChar (Character
);
275 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
276 for (Row
= LocalScreen
.TopRow
+ 1; Row
<= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
- 2; Row
++) {
277 PrintCharAt (LocalScreen
.LeftColumn
, Row
, Character
);
278 PrintCharAt (LocalScreen
.RightColumn
- 1, Row
, Character
);
281 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
282 PrintCharAt (LocalScreen
.LeftColumn
, LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
- 1, Character
);
283 PrintString (Buffer
);
285 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
286 PrintChar (Character
);
288 if (gClassOfVfr
== EFI_SETUP_APPLICATION_SUBCLASS
) {
290 // Print Bottom border line
291 // +------------------------------------------------------------------------------+
293 // +------------------------------------------------------------------------------+
295 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
296 PrintCharAt (LocalScreen
.LeftColumn
, LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
, Character
);
298 PrintString (Buffer
);
300 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
301 PrintChar (Character
);
302 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
303 for (Row
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
+ 1;
304 Row
<= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- 2;
307 PrintCharAt (LocalScreen
.LeftColumn
, Row
, Character
);
308 PrintCharAt (LocalScreen
.RightColumn
- 1, Row
, Character
);
311 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
312 PrintCharAt (LocalScreen
.LeftColumn
, LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- 1, Character
);
314 PrintString (Buffer
);
316 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
317 PrintChar (Character
);
321 gBS
->FreePool (Buffer
);
326 +------------------------------------------------------------------------------+
327 ?F2=Previous Page Setup Page ?
328 +------------------------------------------------------------------------------+
346 +------------------------------------------------------------------------------+
347 ?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ?
348 | ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Discard Changes |
349 +------------------------------------------------------------------------------+
353 OUT UI_MENU_OPTION
*Selection
,
354 IN UINT16 FormHandle
,
355 IN UINT16 TitleToken
,
356 IN EFI_FORM_TAGS FormTags
,
357 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
358 IN UINT8
*CallbackData
364 UINT16 MenuItemCount
;
365 EFI_HII_HANDLE Handle
;
368 EFI_FILE_FORM_TAGS
*FileFormTags
;
373 EFI_SCREEN_DESCRIPTOR LocalScreen
;
376 CHAR16
*OutputString
;
378 Handle
= Selection
->Handle
;
385 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
388 // If we hit a F2 (previous) we already nuked the menu and are simply carrying around what information we need
390 if (Selection
->Previous
) {
391 Selection
->Previous
= FALSE
;
397 StringPtr
= GetToken (TitleToken
, Handle
);
399 if (gClassOfVfr
!= EFI_FRONT_PAGE_SUBCLASS
) {
400 gST
->ConOut
->SetAttribute (gST
->ConOut
, TITLE_TEXT
| TITLE_BACKGROUND
);
402 (LocalScreen
.RightColumn
+ LocalScreen
.LeftColumn
- GetStringWidth (StringPtr
) / 2) / 2,
403 LocalScreen
.TopRow
+ 1,
408 if (gClassOfVfr
== EFI_SETUP_APPLICATION_SUBCLASS
) {
409 gST
->ConOut
->SetAttribute (gST
->ConOut
, KEYHELP_TEXT
| KEYHELP_BACKGROUND
);
412 // Display the infrastructure strings
414 if (!IsListEmpty (&gMenuList
)) {
415 PrintStringAt (LocalScreen
.LeftColumn
+ 2, LocalScreen
.TopRow
+ 1, gFunctionTwoString
);
418 PrintStringAt (LocalScreen
.LeftColumn
+ 2, LocalScreen
.BottomRow
- 4, gFunctionOneString
);
420 LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 3,
421 LocalScreen
.BottomRow
- 4,
425 LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) * 2 / 3,
426 LocalScreen
.BottomRow
- 4,
429 PrintAt (LocalScreen
.LeftColumn
+ 2, LocalScreen
.BottomRow
- 3, (CHAR16
*) L
"%c%c%s", ARROW_UP
, ARROW_DOWN
, gMoveHighlight
);
431 LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 3,
432 LocalScreen
.BottomRow
- 3,
437 // Remove Buffer allocated for StringPtr after it has been used.
439 gBS
->FreePool (StringPtr
);
441 for (Index
= 0; FormTags
.Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
; Index
++) {
446 FileFormTags
= FileFormTagsHead
;
448 if (FormTags
.Tags
[Index
].Operand
== EFI_IFR_FORM_OP
) {
449 FormId
= FormTags
.Tags
[Index
].Id
;
452 // This gives us visibility to the FileFormTags->NvRamMap to check things
453 // ActiveIfr is a global maintained by the menuing code to ensure that we
454 // are pointing to the correct formset's file data.
456 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
457 FileFormTags
= FileFormTags
->NextFile
;
460 // GrayoutIf [SuppressIf]
465 // SuppressIf [GrayoutIf]
473 switch (FormTags
.Tags
[Index
].Operand
) {
474 case EFI_IFR_SUPPRESS_IF_OP
:
477 case EFI_IFR_GRAYOUT_IF_OP
:
482 // Advance to the next op-code
487 // We are now pointing to the beginning of the consistency checking. Let's fast forward
488 // through the AND/OR/NOT data to come up with some meaningful ID data.
491 FormTags
.Tags
[Index
].Operand
== EFI_IFR_AND_OP
||
492 FormTags
.Tags
[Index
].Operand
== EFI_IFR_OR_OP
||
493 FormTags
.Tags
[Index
].Operand
== EFI_IFR_GT_OP
||
494 FormTags
.Tags
[Index
].Operand
== EFI_IFR_GE_OP
||
495 FormTags
.Tags
[Index
].Operand
== EFI_IFR_NOT_OP
;
501 // We need to walk through the consistency checks until we hit the end of the consistency
502 // FALSE means evaluate this single expression
503 // The ConsistencyId refers to which expression in the Consistency database to use
506 Suppress
= ValueIsNotValid (
508 FormTags
.Tags
[Index
].ConsistencyId
,
509 &FormTags
.Tags
[Index
],
515 GrayOut
= ValueIsNotValid (
517 FormTags
.Tags
[Index
].ConsistencyId
,
518 &FormTags
.Tags
[Index
],
524 // Advance to the end of the expression (Will land us at a grayoutif/suppressif or the op-code being affected)
527 FormTags
.Tags
[Index
].Operand
== EFI_IFR_EQ_ID_VAL_OP
||
528 FormTags
.Tags
[Index
].Operand
== EFI_IFR_EQ_VAR_VAL_OP
||
529 FormTags
.Tags
[Index
].Operand
== EFI_IFR_EQ_ID_ID_OP
||
530 FormTags
.Tags
[Index
].Operand
== EFI_IFR_EQ_ID_LIST_OP
||
531 FormTags
.Tags
[Index
].Operand
== EFI_IFR_NOT_OP
||
532 FormTags
.Tags
[Index
].Operand
== EFI_IFR_AND_OP
||
533 FormTags
.Tags
[Index
].Operand
== EFI_IFR_OR_OP
||
534 FormTags
.Tags
[Index
].Operand
== EFI_IFR_TRUE_OP
||
535 FormTags
.Tags
[Index
].Operand
== EFI_IFR_FALSE_OP
||
536 FormTags
.Tags
[Index
].Operand
== EFI_IFR_GT_OP
||
537 FormTags
.Tags
[Index
].Operand
== EFI_IFR_GE_OP
||
538 FormTags
.Tags
[Index
].Operand
== EFI_IFR_LABEL_OP
;
548 // Do this two times (at most will see a suppress and grayout combination
556 FormTags
.Tags
[Index
].GrayOut
= TRUE
;
558 FormTags
.Tags
[Index
].GrayOut
= FALSE
;
560 if (Suppress
&& FormTags
.Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
562 // Only need .Suppress field when the tag is a one_of_option. For other cases, omit them directly.
564 FormTags
.Tags
[Index
].Suppress
= TRUE
;
566 FormTags
.Tags
[Index
].Suppress
= FALSE
;
570 FormTags
.Tags
[Index
].NumberOfLines
> 0 ||
571 FormTags
.Tags
[Index
].Operand
== EFI_IFR_DATE_OP
||
572 FormTags
.Tags
[Index
].Operand
== EFI_IFR_TIME_OP
577 StringPtr
= GetToken (FormTags
.Tags
[Index
].Text
, Handle
);
579 Width
= GetWidth (&FormTags
.Tags
[Index
], Handle
);
582 // This data can be retrieved over and over again. Therefore, reset to original values
583 // before processing otherwise things will start growing linearly
585 if (FormTags
.Tags
[Index
].NumberOfLines
> 1) {
586 FormTags
.Tags
[Index
].NumberOfLines
= 1;
589 for (Count
= 0; GetLineByWidth (StringPtr
, Width
, &ArrayEntry
, &OutputString
) != 0x0000;) {
591 // If there is more string to process print on the next row and increment the Skip value
593 if (StrLen (&StringPtr
[ArrayEntry
])) {
594 FormTags
.Tags
[Index
].NumberOfLines
++;
597 gBS
->FreePool (OutputString
);
603 // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
606 UiAddSubMenuOption (StringPtr
, Handle
, FormTags
.Tags
, Index
, FormId
, MenuItemCount
);
610 // Keep processing menu entries based on the resultant suppress/grayout results until we hit an end-if
613 } while (FormTags
.Tags
[Index
].Operand
!= EFI_IFR_END_IF_OP
&& Conditional
);
616 // We advanced the index for the above conditional, rewind it to keep harmony with the for loop logic
621 Selection
= UiDisplayMenu (TRUE
, FileFormTagsHead
, (EFI_IFR_DATA_ARRAY
*) CallbackData
);
627 InitializeBrowserStrings (
631 gFunctionOneString
= GetToken (STRING_TOKEN (FUNCTION_ONE_STRING
), gHiiHandle
);
632 gFunctionTwoString
= GetToken (STRING_TOKEN (FUNCTION_TWO_STRING
), gHiiHandle
);
633 gFunctionNineString
= GetToken (STRING_TOKEN (FUNCTION_NINE_STRING
), gHiiHandle
);
634 gFunctionTenString
= GetToken (STRING_TOKEN (FUNCTION_TEN_STRING
), gHiiHandle
);
635 gEnterString
= GetToken (STRING_TOKEN (ENTER_STRING
), gHiiHandle
);
636 gEnterCommitString
= GetToken (STRING_TOKEN (ENTER_COMMIT_STRING
), gHiiHandle
);
637 gEscapeString
= GetToken (STRING_TOKEN (ESCAPE_STRING
), gHiiHandle
);
638 gMoveHighlight
= GetToken (STRING_TOKEN (MOVE_HIGHLIGHT
), gHiiHandle
);
639 gMakeSelection
= GetToken (STRING_TOKEN (MAKE_SELECTION
), gHiiHandle
);
640 gNumericInput
= GetToken (STRING_TOKEN (NUMERIC_INPUT
), gHiiHandle
);
641 gToggleCheckBox
= GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX
), gHiiHandle
);
642 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
643 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
644 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
645 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
646 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
647 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
648 gAreYouSure
= GetToken (STRING_TOKEN (ARE_YOU_SURE
), gHiiHandle
);
649 gYesResponse
= GetToken (STRING_TOKEN (ARE_YOU_SURE_YES
), gHiiHandle
);
650 gNoResponse
= GetToken (STRING_TOKEN (ARE_YOU_SURE_NO
), gHiiHandle
);
651 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
652 gPlusString
= GetToken (STRING_TOKEN (PLUS_STRING
), gHiiHandle
);
653 gMinusString
= GetToken (STRING_TOKEN (MINUS_STRING
), gHiiHandle
);
654 gAdjustNumber
= GetToken (STRING_TOKEN (ADJUST_NUMBER
), gHiiHandle
);
660 IN UI_MENU_OPTION
*Selection
,
665 Update key's help imformation
668 Selection C The form that current display
669 Selected C Whether or not a tag be selected
677 UINTN LeftColumnOfHelp
;
678 UINTN RightColumnOfHelp
;
680 UINTN BottomRowOfHelp
;
681 UINTN StartColumnOfHelp
;
682 EFI_SCREEN_DESCRIPTOR LocalScreen
;
684 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
686 SecCol
= LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 3;
687 ThdCol
= LocalScreen
.LeftColumn
+ (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) * 2 / 3;
689 StartColumnOfHelp
= LocalScreen
.LeftColumn
+ 2;
690 LeftColumnOfHelp
= LocalScreen
.LeftColumn
+ 1;
691 RightColumnOfHelp
= LocalScreen
.RightColumn
- 2;
692 TopRowOfHelp
= LocalScreen
.BottomRow
- 4;
693 BottomRowOfHelp
= LocalScreen
.BottomRow
- 3;
695 if (gClassOfVfr
== EFI_GENERAL_APPLICATION_SUBCLASS
) {
699 gST
->ConOut
->SetAttribute (gST
->ConOut
, KEYHELP_TEXT
| KEYHELP_BACKGROUND
);
701 switch (Selection
->ThisTag
->Operand
) {
702 case EFI_IFR_ORDERED_LIST_OP
:
703 case EFI_IFR_ONE_OF_OP
:
704 case EFI_IFR_NUMERIC_OP
:
705 case EFI_IFR_TIME_OP
:
706 case EFI_IFR_DATE_OP
:
707 ClearLines (LeftColumnOfHelp
, RightColumnOfHelp
, TopRowOfHelp
, BottomRowOfHelp
, KEYHELP_TEXT
| KEYHELP_BACKGROUND
);
710 if (gClassOfVfr
== EFI_SETUP_APPLICATION_SUBCLASS
) {
711 PrintStringAt (StartColumnOfHelp
, TopRowOfHelp
, gFunctionOneString
);
712 PrintStringAt (SecCol
, TopRowOfHelp
, gFunctionNineString
);
713 PrintStringAt (ThdCol
, TopRowOfHelp
, gFunctionTenString
);
714 PrintStringAt (ThdCol
, BottomRowOfHelp
, gEscapeString
);
718 if ((Selection
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (Selection
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
722 (CHAR16
*) L
"%c%c%c%c%s",
729 PrintStringAt (SecCol
, BottomRowOfHelp
, gAdjustNumber
);
731 PrintAt (StartColumnOfHelp
, BottomRowOfHelp
, (CHAR16
*) L
"%c%c%s", ARROW_UP
, ARROW_DOWN
, gMoveHighlight
);
732 PrintStringAt (SecCol
, BottomRowOfHelp
, gEnterString
);
735 PrintStringAt (StartColumnOfHelp
, BottomRowOfHelp
, gEnterCommitString
);
738 // If it is a selected numeric with manual input, display different message
740 if ((Selection
->ThisTag
->Operand
== EFI_IFR_NUMERIC_OP
) && (Selection
->ThisTag
->Step
== 0)) {
741 PrintStringAt (SecCol
, TopRowOfHelp
, gNumericInput
);
742 } else if (Selection
->ThisTag
->Operand
!= EFI_IFR_ORDERED_LIST_OP
) {
743 PrintAt (SecCol
, BottomRowOfHelp
, (CHAR16
*) L
"%c%c%s", ARROW_UP
, ARROW_DOWN
, gMoveHighlight
);
746 if (Selection
->ThisTag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
747 PrintStringAt (StartColumnOfHelp
, TopRowOfHelp
, gPlusString
);
748 PrintStringAt (ThdCol
, TopRowOfHelp
, gMinusString
);
751 PrintStringAt (ThdCol
, BottomRowOfHelp
, gEscapeString
);
755 case EFI_IFR_CHECKBOX_OP
:
756 ClearLines (LeftColumnOfHelp
, RightColumnOfHelp
, TopRowOfHelp
, BottomRowOfHelp
, KEYHELP_TEXT
| KEYHELP_BACKGROUND
);
758 if (gClassOfVfr
== EFI_SETUP_APPLICATION_SUBCLASS
) {
759 PrintStringAt (StartColumnOfHelp
, TopRowOfHelp
, gFunctionOneString
);
760 PrintStringAt (SecCol
, TopRowOfHelp
, gFunctionNineString
);
761 PrintStringAt (ThdCol
, TopRowOfHelp
, gFunctionTenString
);
762 PrintStringAt (ThdCol
, BottomRowOfHelp
, gEscapeString
);
765 PrintAt (StartColumnOfHelp
, BottomRowOfHelp
, (CHAR16
*) L
"%c%c%s", ARROW_UP
, ARROW_DOWN
, gMoveHighlight
);
766 PrintStringAt (SecCol
, BottomRowOfHelp
, gToggleCheckBox
);
770 case EFI_IFR_PASSWORD_OP
:
771 case EFI_IFR_STRING_OP
:
772 ClearLines (LeftColumnOfHelp
, RightColumnOfHelp
, TopRowOfHelp
, BottomRowOfHelp
, KEYHELP_TEXT
| KEYHELP_BACKGROUND
);
775 if (gClassOfVfr
== EFI_SETUP_APPLICATION_SUBCLASS
) {
776 PrintStringAt (StartColumnOfHelp
, TopRowOfHelp
, gFunctionOneString
);
777 PrintStringAt (SecCol
, TopRowOfHelp
, gFunctionNineString
);
778 PrintStringAt (ThdCol
, TopRowOfHelp
, gFunctionTenString
);
779 PrintStringAt (ThdCol
, BottomRowOfHelp
, gEscapeString
);
782 PrintAt (StartColumnOfHelp
, BottomRowOfHelp
, (CHAR16
*) L
"%c%c%s", ARROW_UP
, ARROW_DOWN
, gMoveHighlight
);
783 PrintStringAt (SecCol
, BottomRowOfHelp
, gEnterString
);
785 if (Selection
->ThisTag
->Operand
!= EFI_IFR_REF_OP
) {
787 (LocalScreen
.RightColumn
- GetStringWidth (gEnterCommitString
) / 2) / 2,
791 PrintStringAt (ThdCol
, BottomRowOfHelp
, gEscapeString
);
801 IN UI_MENU_OPTION
*Selection
,
802 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
804 OUT UINT16
*FormHandle
,
805 OUT UINT16
*TitleToken
,
806 OUT EFI_FORM_TAGS
*FormTags
810 EFI_FILE_FORM_TAGS
*FileFormTags
;
811 EFI_FORM_TAGS LocalTags
;
813 FileFormTags
= FileFormTagsHead
;
816 // Advance FileFormTags to the correct file's tag information.
817 // For instance, if Selection->IfrNumber is 3, that means the 4th
818 // file (0-based) in the FileFormTags linked-list contains the tag
821 for (Index
= 0; Index
< Selection
->IfrNumber
; Index
++) {
822 FileFormTags
= FileFormTags
->NextFile
;
825 LocalTags
= FileFormTags
->FormTags
;
829 // Advance Index to the first FormOp tag information
831 for (Index
= 0; FileFormTags
->FormTags
.Tags
[Index
].Operand
!= EFI_IFR_FORM_OP
; Index
++)
835 // Advance Index to the FormOp with the correct ID value
837 for (; LocalTags
.Next
!= NULL
; LocalTags
= *LocalTags
.Next
) {
838 for (Index
= 0; LocalTags
.Tags
[Index
].Operand
!= EFI_IFR_FORM_OP
; Index
++)
840 if (LocalTags
.Tags
[Index
].Id
== IdValue
) {
846 // return the Form Id, Text, and the File's FormTags structure
848 *FormHandle
= LocalTags
.Tags
[Index
].Id
;
849 *TitleToken
= LocalTags
.Tags
[Index
].Text
;
850 *FormTags
= LocalTags
;
857 IN UINT16 ConsistencyId
,
858 IN UINT16 CurrentVariable
,
859 IN EFI_FORM_TAGS
*FormTags
,
860 OUT EFI_FILE_FORM_TAGS
*FileFormTags
865 UINT16 QuestionIndex
;
873 // Initialize some Index variable and Status
879 Status
= EFI_SUCCESS
;
883 // Determine the number of tags for the first form
885 GetTagCount (&FormData
[Index
], &NumberOfTags
);
888 // Allocate memory for our tags on the first form
890 FormTags
->Tags
= AllocateZeroPool (NumberOfTags
* sizeof (EFI_TAG
));
891 ASSERT (FormTags
->Tags
!= NULL
);
893 for (CurrTag
= 0; FormData
[Index
] != EFI_IFR_END_FORM_SET_OP
; CurrTag
++) {
895 // Operand = IFR OpCode
897 FormTags
->Tags
[CurrTag
].Operand
= FormData
[Index
];
900 // Assume for now 0 lines occupied by this OpCode
902 FormTags
->Tags
[CurrTag
].NumberOfLines
= 0;
905 // Determine the length of the Tag so we can later skip to the next tag in the form
910 TagLength
= FormData
[Index
+ 1];
912 // Operate on the Found OpCode
914 switch (FormData
[Index
]) {
916 case EFI_IFR_FORM_OP
:
917 case EFI_IFR_SUBTITLE_OP
:
918 case EFI_IFR_TEXT_OP
:
920 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
923 case EFI_IFR_VARSTORE_SELECT_OP
:
924 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
925 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT
*) &FormData
[Index
])->VarId
, sizeof (UINT16
));
928 case EFI_IFR_END_FORM_OP
:
929 FormTags
->Tags
[CurrTag
].Operand
= FormData
[Index
];
930 FormTags
->Tags
[CurrTag
].NumberOfLines
= 0;
935 case EFI_IFR_ORDERED_LIST_OP
:
936 case EFI_IFR_ONE_OF_OP
:
937 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], FormData
, Index
, FileFormTags
, CurrentVariable
);
940 // Store away the CurrTag since what follows will be the answer that we
941 // need to place into the appropriate location in the tag array
944 // record for setting default later
946 QuestionIndex
= (UINT16
) CurrTag
;
949 case EFI_IFR_ONE_OF_OPTION_OP
:
950 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
951 FormTags
->Tags
[QuestionIndex
].Key
= ((EFI_IFR_ONE_OF_OPTION
*) &FormData
[Index
])->Key
;
952 FormTags
->Tags
[QuestionIndex
].ResetRequired
= (BOOLEAN
) (FormTags
->Tags
[QuestionIndex
].Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
955 case EFI_IFR_CHECKBOX_OP
:
956 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], FormData
, Index
, FileFormTags
, CurrentVariable
);
957 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
960 case EFI_IFR_NUMERIC_OP
:
961 GetNumericHeader (&FormTags
->Tags
[CurrTag
], FormData
, Index
, (UINT16
) 1, FileFormTags
, CurrentVariable
);
962 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
965 case EFI_IFR_DATE_OP
:
967 // Date elements come in as a Year, Month, Day. We need to process them as a country-based
968 // Order. It is much easier to do it here than anywhere else.
970 // For US standards - we want Month/Day/Year, thus we advance "i" +1, +2, +0 while CurrTag is +0, +1, +2
973 &FormTags
->Tags
[CurrTag
],
975 (UINT16
) (Index
+ TagLength
),
982 // The current language selected + the Date operand
984 FormTags
->Tags
[CurrTag
+ 1].Operand
= FormData
[Index
];
986 &FormTags
->Tags
[CurrTag
+ 1],
988 (UINT16
) (Index
+ TagLength
+ FormData
[Index
+ TagLength
+ 1]),
995 // The current language selected + the Date operand
997 FormTags
->Tags
[CurrTag
+ 2].Operand
= FormData
[Index
];
998 GetNumericHeader (&FormTags
->Tags
[CurrTag
+ 2], FormData
, Index
, (UINT16
) 1, FileFormTags
, CurrentVariable
);
1000 CurrTag
= (INT16
) (CurrTag
+ 2);
1002 Index
= (UINT16
) (Index
+ TagLength
);
1006 TagLength
= FormData
[Index
+ 1];
1007 Index
= (UINT16
) (Index
+ TagLength
);
1011 TagLength
= FormData
[Index
+ 1];
1014 case EFI_IFR_TIME_OP
:
1015 GetNumericHeader (&FormTags
->Tags
[CurrTag
], FormData
, Index
, (UINT16
) 0, FileFormTags
, CurrentVariable
);
1019 // Override the GetQuestionHeader information - date/time are treated very differently
1021 FormTags
->Tags
[CurrTag
].NumberOfLines
= 1;
1025 // The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines
1026 // associated with them, and the third has 1 line to allow to space beyond the choice.
1032 case EFI_IFR_PASSWORD_OP
:
1033 case EFI_IFR_STRING_OP
:
1034 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], FormData
, Index
, FileFormTags
, CurrentVariable
);
1035 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
1038 case EFI_IFR_INCONSISTENT_IF_OP
:
1039 case EFI_IFR_SUPPRESS_IF_OP
:
1040 case EFI_IFR_GRAYOUT_IF_OP
:
1044 case EFI_IFR_EQ_ID_VAL_OP
:
1045 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
1046 FormTags
->Tags
[CurrTag
].ConsistencyId
= ConsistencyId
;
1049 case EFI_IFR_EQ_VAR_VAL_OP
:
1050 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
1051 FormTags
->Tags
[CurrTag
].ConsistencyId
= ConsistencyId
;
1054 case EFI_IFR_EQ_ID_ID_OP
:
1055 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
1056 FormTags
->Tags
[CurrTag
].ConsistencyId
= ConsistencyId
;
1059 case EFI_IFR_AND_OP
:
1061 case EFI_IFR_NOT_OP
:
1062 case EFI_IFR_TRUE_OP
:
1063 case EFI_IFR_FALSE_OP
:
1066 FormTags
->Tags
[CurrTag
].ConsistencyId
= ConsistencyId
;
1069 case EFI_IFR_EQ_ID_LIST_OP
:
1070 IfrToFormTag (FormData
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &FormData
[Index
], NULL
);
1072 FormTags
->Tags
[CurrTag
].ConsistencyId
= ConsistencyId
;
1085 // Per spec., we ignore ops that we don't know how to deal with. Skip to next tag
1087 Index
= (UINT16
) (Index
+ TagLength
);
1096 ExtractDynamicFormHandle (
1097 IN UI_MENU_OPTION
*Selection
,
1098 IN UINT8
*CallbackData
,
1099 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1101 OUT UINT16
*FormHandle
,
1102 OUT UINT16
*TitleToken
,
1103 OUT EFI_FORM_TAGS
*FormTags
1107 Routine Description:
1109 The function does the most of the works when the EFI_TAG that
1110 user selects on is EFI_IFR_FLAG_INTERACTIVE or EFI_IFR_PASSWORD_OP:
1111 invoke CallBack, update the new form data.
1115 Selection - The current selection of the form.
1116 CallbackData - The pointer to host the data passed back by the callback function.
1117 FileFormTagsHead - Prompt string token of the one-of box
1118 IdValue - The current page number.
1119 FormHandle - Output the the handle of the form.
1120 TitleToken - Output the TitleToken of the new page.
1121 FormTags - Output the FormFags of the new page.
1130 EFI_FILE_FORM_TAGS
*FileFormTags
;
1131 EFI_FORM_TAGS
*LocalTags
;
1132 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1136 EFI_PHYSICAL_ADDRESS CallbackHandle
;
1139 EFI_HII_CALLBACK_PACKET
*Packet
;
1141 CHAR16 NullCharacter
;
1143 UINT16 ConsistencyId
;
1144 UINT16 CurrentVariable
;
1145 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1146 EFI_IFR_DATA_ENTRY
*DataEntry
;
1148 VariableDefinition
= NULL
;
1149 NullCharacter
= CHAR_NULL
;
1151 CurrentVariable
= 0;
1152 FileFormTags
= FileFormTagsHead
;
1155 TargetPage
= (UINT16
) IdValue
;
1160 // Advance FileFormTags to the correct file's tag information.
1161 // For instance, if Selection->IfrNumber is 3, that means the 4th
1162 // file (0-based) in the FileFormTags linked-list contains the tag
1165 for (Index
= 0; Index
< Selection
->IfrNumber
; Index
++) {
1166 FileFormTags
= FileFormTags
->NextFile
;
1169 LocalTags
= &FileFormTags
->FormTags
;
1172 // Advance Index to the FormOp with the correct ID value
1174 for (; LocalTags
->Next
!= NULL
; LocalTags
= LocalTags
->Next
) {
1175 if ((LocalTags
->Tags
[0].CallbackHandle
!= 0) && (CallbackHandle
== 0)) {
1176 CallbackHandle
= LocalTags
->Tags
[0].CallbackHandle
;
1177 CopyMem (&TagGuid
, &LocalTags
->Tags
[0].GuidValue
, sizeof (EFI_GUID
));
1180 for (Index
= 0; LocalTags
->Tags
[Index
].Operand
!= EFI_IFR_FORM_OP
; Index
++)
1182 if (LocalTags
->Tags
[Index
].Id
== IdValue
) {
1187 // If we are going to callback on a non-goto opcode, make sure we don't change pages
1189 if (Selection
->ThisTag
->Operand
!= EFI_IFR_REF_OP
) {
1190 TargetPage
= Selection
->FormId
;
1193 // The first tag below should be the form op-code. We need to store away the
1194 // current variable setting to ensure if we have to reload the page, that we
1195 // can correctly restore the values for the active variable
1197 CurrentVariable
= Selection
->Tags
[0].VariableNumber
;
1200 // Remember that dynamic pages in an environment where all pages are not
1201 // dynamic require us to call back to the user to give them an opportunity
1202 // to register fresh information in the HII database so that we can extract it.
1204 Status
= gBS
->HandleProtocol (
1205 (VOID
*) (UINTN
) CallbackHandle
,
1206 &gEfiFormCallbackProtocolGuid
,
1207 (VOID
**) &FormCallback
1210 if (EFI_ERROR (Status
)) {
1211 gBS
->FreePool (LocalTags
->Tags
);
1215 ExtractRequestedNvMap (FileFormTags
, CurrentVariable
, &VariableDefinition
);
1217 if (Selection
->ThisTag
->Flags
& (EFI_IFR_FLAG_INTERACTIVE
| EFI_IFR_FLAG_NV_ACCESS
)) {
1218 ((EFI_IFR_DATA_ARRAY
*) CallbackData
)->NvRamMap
= VariableDefinition
->NvRamMap
;
1220 ((EFI_IFR_DATA_ARRAY
*) CallbackData
)->NvRamMap
= NULL
;
1223 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
1224 Status
= FormCallback
->Callback (
1226 Selection
->ThisTag
->Key
,
1227 (EFI_IFR_DATA_ARRAY
*) CallbackData
,
1232 if (EFI_ERROR (Status
)) {
1234 // Restore Previous Value
1237 &VariableDefinition
->NvRamMap
[Selection
->ThisTag
->StorageStart
],
1239 Selection
->ThisTag
->StorageWidth
1242 if (Packet
!= NULL
) {
1244 // Upon error, we will likely receive a string to print out
1246 ScreenSize
= GetStringWidth (Packet
->String
) / 2;
1249 // Display error popup
1251 CreatePopUp (ScreenSize
, 3, &NullCharacter
, Packet
->String
, &NullCharacter
);
1254 Status
= WaitForKeyStroke (&Key
);
1255 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1257 UpdateStatusBar (INPUT_ERROR
, (UINT8
) 0, TRUE
);
1261 if (Packet
!= NULL
) {
1263 // We need to on a non-error, look in the outbound Packet for information and update the NVRAM
1264 // location associated with the op-code specified there. This is used on single op-code instances
1265 // and not for when a hyperlink sent us a whole page of data.
1267 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (&Packet
->DataArray
+ 1);
1268 if (Packet
->DataArray
.EntryCount
== 1) {
1269 switch (DataEntry
->OpCode
) {
1270 case EFI_IFR_STRING_OP
:
1271 case EFI_IFR_NUMERIC_OP
:
1272 case EFI_IFR_ORDERED_LIST_OP
:
1273 case EFI_IFR_ONE_OF_OP
:
1274 case EFI_IFR_CHECKBOX_OP
:
1276 &VariableDefinition
->NvRamMap
[Selection
->ThisTag
->StorageStart
],
1278 Selection
->ThisTag
->StorageWidth
1282 case EFI_IFR_NV_ACCESS_COMMAND
:
1284 &VariableDefinition
->NvRamMap
[((EFI_IFR_NV_DATA
*) Packet
)->QuestionId
],
1285 ((EFI_IFR_NV_DATA
*) Packet
) + 1,
1286 ((EFI_IFR_NV_DATA
*) Packet
)->StorageWidth
1292 if (DataEntry
->Flags
& RESET_REQUIRED
) {
1293 gResetRequired
= TRUE
;
1296 if (DataEntry
->Flags
& EXIT_REQUIRED
) {
1297 gExitRequired
= TRUE
;
1300 if (DataEntry
->Flags
& SAVE_REQUIRED
) {
1301 gSaveRequired
= TRUE
;
1304 if (DataEntry
->Flags
& NV_CHANGED
) {
1305 gNvUpdateRequired
= TRUE
;
1308 if (DataEntry
->Flags
& NV_NOT_CHANGED
) {
1309 gNvUpdateRequired
= FALSE
;
1315 if (Packet
!= NULL
) {
1316 gBS
->FreePool (Packet
);
1319 for (BackupIndex
= 0; LocalTags
->Tags
[BackupIndex
].Operand
!= EFI_IFR_END_FORM_OP
; BackupIndex
++) {
1320 switch (LocalTags
->Tags
[BackupIndex
].Operand
) {
1321 case EFI_IFR_EQ_VAR_VAL_OP
:
1322 case EFI_IFR_EQ_ID_VAL_OP
:
1323 case EFI_IFR_EQ_ID_ID_OP
:
1324 case EFI_IFR_AND_OP
:
1326 case EFI_IFR_NOT_OP
:
1327 case EFI_IFR_TRUE_OP
:
1328 case EFI_IFR_FALSE_OP
:
1331 case EFI_IFR_EQ_ID_LIST_OP
:
1333 // If we encountered a ConsistencyId value, on this page they will be incremental
1334 // So register the first value we encounter. We will pass this in when we re-create this page
1336 if ((LocalTags
->Tags
[BackupIndex
].ConsistencyId
!= 0) && (ConsistencyId
== 0)) {
1337 ConsistencyId
= (UINT16
) (LocalTags
->Tags
[BackupIndex
].ConsistencyId
- 1);
1343 // Delete the buffer associated with previous dynamic page
1344 // We will re-allocate a buffer....
1346 gBS
->FreePool (LocalTags
->Tags
);
1349 Buffer
= AllocateZeroPool (Length
);
1350 ASSERT (Buffer
!= NULL
);
1353 // Get the form that was updated by the callback
1364 // Ok, we have the new page.....now we must purge the old page and re-allocate
1365 // the tag page with the new data
1376 // return the Form Id, Text, and the File's FormTags structure
1378 *FormHandle
= LocalTags
->Tags
[0].Id
;
1379 *TitleToken
= LocalTags
->Tags
[0].Text
;
1380 *FormTags
= *LocalTags
;
1382 FormTags
->Tags
[0].CallbackHandle
= CallbackHandle
;
1383 CopyMem (&FormTags
->Tags
[0].GuidValue
, &TagGuid
, sizeof (EFI_GUID
));
1390 IN UI_MENU_OPTION
*Selection
,
1391 IN BOOLEAN Callback
,
1392 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1393 IN UINT8
*CallbackData
1398 EFI_FORM_TAGS FormTags
;
1403 // Displays the Header and Footer borders
1405 DisplayPageFrame ();
1408 // Id of 0 yields the getting of the top form whatever the ID is. Usually the first form in the IFR
1410 ExtractFormHandle (Selection
, FileFormTagsHead
, 0, &FormHandle
, &TitleToken
, &FormTags
);
1412 Selection
= DisplayForm (Selection
, FormHandle
, TitleToken
, FormTags
, FileFormTagsHead
, CallbackData
);
1415 // If selection is null use the former selection
1417 if (Selection
== NULL
) {
1425 while (Selection
->Tags
!= NULL
) {
1426 if (Selection
->Previous
) {
1427 ExtractFormHandle (Selection
, FileFormTagsHead
, Selection
->FormId
, &FormHandle
, &TitleToken
, &FormTags
);
1430 // True if a hyperlink/jump is selected
1432 if (Selection
->ThisTag
->Operand
== EFI_IFR_REF_OP
&& Selection
->ThisTag
->Id
!= 0x0000) {
1433 if (Selection
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
1434 ExtractDynamicFormHandle (
1438 Selection
->ThisTag
->Id
,
1445 ExtractFormHandle (Selection
, FileFormTagsHead
, Selection
->ThisTag
->Id
, &FormHandle
, &TitleToken
, &FormTags
);
1450 if ((Selection
->ThisTag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) &&
1451 (Selection
->ThisTag
->Operand
!= EFI_IFR_PASSWORD_OP
)
1453 ExtractDynamicFormHandle (
1463 ExtractFormHandle (Selection
, FileFormTagsHead
, Selection
->FormId
, &FormHandle
, &TitleToken
, &FormTags
);
1469 // Displays the Header and Footer borders
1471 DisplayPageFrame ();
1473 Selection
= DisplayForm (Selection
, FormHandle
, TitleToken
, FormTags
, FileFormTagsHead
, CallbackData
);
1475 if (Selection
== NULL
) {