mirror of https://github.com/acidanthera/audk.git
1486 lines
47 KiB
C
1486 lines
47 KiB
C
/*++
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
Presentation.c
|
|
|
|
Abstract:
|
|
|
|
Some presentation routines.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "Setup.h"
|
|
#include "Ui.h"
|
|
#include "Colors.h"
|
|
|
|
VOID
|
|
ClearLines (
|
|
UINTN LeftColumn,
|
|
UINTN RightColumn,
|
|
UINTN TopRow,
|
|
UINTN BottomRow,
|
|
UINTN TextAttribute
|
|
)
|
|
{
|
|
CHAR16 *Buffer;
|
|
UINTN Row;
|
|
|
|
//
|
|
// For now, allocate an arbitrarily long buffer
|
|
//
|
|
Buffer = AllocateZeroPool (0x10000);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
//
|
|
// Set foreground and background as defined
|
|
//
|
|
gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);
|
|
|
|
//
|
|
// Much faster to buffer the long string instead of print it a character at a time
|
|
//
|
|
SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');
|
|
|
|
//
|
|
// Clear the desired area with the appropriate foreground/background
|
|
//
|
|
for (Row = TopRow; Row <= BottomRow; Row++) {
|
|
PrintStringAt (LeftColumn, Row, Buffer);
|
|
}
|
|
|
|
gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);
|
|
|
|
gBS->FreePool (Buffer);
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
NewStrCat (
|
|
CHAR16 *Destination,
|
|
CHAR16 *Source
|
|
)
|
|
{
|
|
UINTN Length;
|
|
|
|
for (Length = 0; Destination[Length] != 0; Length++)
|
|
;
|
|
|
|
//
|
|
// We now have the length of the original string
|
|
// We can safely assume for now that we are concatenating a narrow value to this string.
|
|
// For instance, the string is "XYZ" and cat'ing ">"
|
|
// If this assumption changes, we need to make this routine a bit more complex
|
|
//
|
|
Destination[Length] = (CHAR16) NARROW_CHAR;
|
|
Length++;
|
|
|
|
StrCpy (Destination + Length, Source);
|
|
}
|
|
|
|
UINTN
|
|
GetStringWidth (
|
|
CHAR16 *String
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Count;
|
|
UINTN IncrementValue;
|
|
|
|
Index = 0;
|
|
Count = 0;
|
|
IncrementValue = 1;
|
|
|
|
do {
|
|
//
|
|
// Advance to the null-terminator or to the first width directive
|
|
//
|
|
for (;
|
|
(String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
|
|
Index++, Count = Count + IncrementValue
|
|
)
|
|
;
|
|
|
|
//
|
|
// We hit the null-terminator, we now have a count
|
|
//
|
|
if (String[Index] == 0) {
|
|
break;
|
|
}
|
|
//
|
|
// We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
|
|
// and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
|
|
//
|
|
if (String[Index] == NARROW_CHAR) {
|
|
//
|
|
// Skip to the next character
|
|
//
|
|
Index++;
|
|
IncrementValue = 1;
|
|
} else {
|
|
//
|
|
// Skip to the next character
|
|
//
|
|
Index++;
|
|
IncrementValue = 2;
|
|
}
|
|
} while (String[Index] != 0);
|
|
|
|
//
|
|
// Increment by one to include the null-terminator in the size
|
|
//
|
|
Count++;
|
|
|
|
return Count * sizeof (CHAR16);
|
|
}
|
|
|
|
VOID
|
|
DisplayPageFrame (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT8 Line;
|
|
UINT8 Alignment;
|
|
CHAR16 Character;
|
|
CHAR16 *Buffer;
|
|
CHAR16 *StrFrontPageBanner;
|
|
EFI_SCREEN_DESCRIPTOR LocalScreen;
|
|
UINTN Row;
|
|
|
|
ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow);
|
|
ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND);
|
|
|
|
CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
|
|
//
|
|
// For now, allocate an arbitrarily long buffer
|
|
//
|
|
Buffer = AllocateZeroPool (0x10000);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
Character = (CHAR16) BOXDRAW_HORIZONTAL;
|
|
|
|
for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {
|
|
Buffer[Index] = Character;
|
|
}
|
|
|
|
if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
|
|
//
|
|
// ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
|
|
//
|
|
ClearLines (
|
|
LocalScreen.LeftColumn,
|
|
LocalScreen.RightColumn,
|
|
LocalScreen.TopRow,
|
|
FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow,
|
|
BANNER_TEXT | BANNER_BACKGROUND
|
|
);
|
|
//
|
|
// for (Line = 0; Line < BANNER_HEIGHT; Line++) {
|
|
//
|
|
for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {
|
|
//
|
|
// for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
|
|
//
|
|
for (Alignment = (UINT8) LocalScreen.LeftColumn;
|
|
Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn;
|
|
Alignment++
|
|
) {
|
|
if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) {
|
|
StrFrontPageBanner = GetToken (
|
|
BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn],
|
|
FrontPageHandle
|
|
);
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
switch (Alignment - LocalScreen.LeftColumn) {
|
|
case 0:
|
|
//
|
|
// Handle left column
|
|
//
|
|
PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner);
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// Handle center column
|
|
//
|
|
PrintStringAt (
|
|
LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
|
|
Line,
|
|
StrFrontPageBanner
|
|
);
|
|
break;
|
|
|
|
case 2:
|
|
//
|
|
// Handle right column
|
|
//
|
|
PrintStringAt (
|
|
LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,
|
|
Line,
|
|
StrFrontPageBanner
|
|
);
|
|
break;
|
|
}
|
|
|
|
gBS->FreePool (StrFrontPageBanner);
|
|
}
|
|
}
|
|
}
|
|
|
|
ClearLines (
|
|
LocalScreen.LeftColumn,
|
|
LocalScreen.RightColumn,
|
|
LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT,
|
|
LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,
|
|
KEYHELP_TEXT | KEYHELP_BACKGROUND
|
|
);
|
|
|
|
if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
|
|
ClearLines (
|
|
LocalScreen.LeftColumn,
|
|
LocalScreen.RightColumn,
|
|
LocalScreen.TopRow,
|
|
LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1,
|
|
TITLE_TEXT | TITLE_BACKGROUND
|
|
);
|
|
//
|
|
// Print Top border line
|
|
// +------------------------------------------------------------------------------+
|
|
// ? ?
|
|
// +------------------------------------------------------------------------------+
|
|
//
|
|
Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
|
|
|
|
PrintChar (Character);
|
|
PrintString (Buffer);
|
|
|
|
Character = (CHAR16) BOXDRAW_DOWN_LEFT;
|
|
PrintChar (Character);
|
|
|
|
Character = (CHAR16) BOXDRAW_VERTICAL;
|
|
for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
|
|
PrintCharAt (LocalScreen.LeftColumn, Row, Character);
|
|
PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
|
|
}
|
|
|
|
Character = (CHAR16) BOXDRAW_UP_RIGHT;
|
|
PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
|
|
PrintString (Buffer);
|
|
|
|
Character = (CHAR16) BOXDRAW_UP_LEFT;
|
|
PrintChar (Character);
|
|
|
|
if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
|
|
//
|
|
// Print Bottom border line
|
|
// +------------------------------------------------------------------------------+
|
|
// ? ?
|
|
// +------------------------------------------------------------------------------+
|
|
//
|
|
Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
|
|
PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character);
|
|
|
|
PrintString (Buffer);
|
|
|
|
Character = (CHAR16) BOXDRAW_DOWN_LEFT;
|
|
PrintChar (Character);
|
|
Character = (CHAR16) BOXDRAW_VERTICAL;
|
|
for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1;
|
|
Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;
|
|
Row++
|
|
) {
|
|
PrintCharAt (LocalScreen.LeftColumn, Row, Character);
|
|
PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
|
|
}
|
|
|
|
Character = (CHAR16) BOXDRAW_UP_RIGHT;
|
|
PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
|
|
|
|
PrintString (Buffer);
|
|
|
|
Character = (CHAR16) BOXDRAW_UP_LEFT;
|
|
PrintChar (Character);
|
|
}
|
|
}
|
|
|
|
gBS->FreePool (Buffer);
|
|
|
|
}
|
|
|
|
/*
|
|
+------------------------------------------------------------------------------+
|
|
?F2=Previous Page Setup Page ?
|
|
+------------------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+------------------------------------------------------------------------------+
|
|
?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ?
|
|
| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Discard Changes |
|
|
+------------------------------------------------------------------------------+
|
|
*/
|
|
STATIC
|
|
UI_MENU_OPTION *
|
|
DisplayForm (
|
|
OUT UI_MENU_OPTION *Selection,
|
|
IN UINT16 FormHandle,
|
|
IN UINT16 TitleToken,
|
|
IN EFI_FORM_TAGS FormTags,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINT8 *CallbackData
|
|
)
|
|
{
|
|
CHAR16 *StringPtr;
|
|
UINTN Index;
|
|
UINTN Count;
|
|
UINT16 MenuItemCount;
|
|
EFI_HII_HANDLE Handle;
|
|
UINT16 FormId;
|
|
STRING_REF String;
|
|
EFI_FILE_FORM_TAGS *FileFormTags;
|
|
BOOLEAN SuppressIf;
|
|
BOOLEAN Suppress;
|
|
BOOLEAN GrayOut;
|
|
BOOLEAN Conditional;
|
|
EFI_SCREEN_DESCRIPTOR LocalScreen;
|
|
UINT16 Width;
|
|
UINTN ArrayEntry;
|
|
CHAR16 *OutputString;
|
|
|
|
Handle = Selection->Handle;
|
|
FormId = 0;
|
|
String = 0;
|
|
MenuItemCount = 0;
|
|
ArrayEntry = 0;
|
|
OutputString = NULL;
|
|
|
|
CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
|
|
//
|
|
// If we hit a F2 (previous) we already nuked the menu and are simply carrying around what information we need
|
|
//
|
|
if (Selection->Previous) {
|
|
Selection->Previous = FALSE;
|
|
} else {
|
|
UiFreeMenu ();
|
|
UiInitMenu ();
|
|
}
|
|
|
|
StringPtr = GetToken (TitleToken, Handle);
|
|
|
|
if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
|
|
gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
|
|
PrintStringAt (
|
|
(LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,
|
|
LocalScreen.TopRow + 1,
|
|
StringPtr
|
|
);
|
|
}
|
|
|
|
if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
|
|
gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
|
|
|
|
//
|
|
// Display the infrastructure strings
|
|
//
|
|
if (!IsListEmpty (&gMenuList)) {
|
|
PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString);
|
|
}
|
|
|
|
PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString);
|
|
PrintStringAt (
|
|
LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
|
|
LocalScreen.BottomRow - 4,
|
|
gFunctionNineString
|
|
);
|
|
PrintStringAt (
|
|
LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,
|
|
LocalScreen.BottomRow - 4,
|
|
gFunctionTenString
|
|
);
|
|
PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
|
|
PrintStringAt (
|
|
LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
|
|
LocalScreen.BottomRow - 3,
|
|
gEscapeString
|
|
);
|
|
}
|
|
//
|
|
// Remove Buffer allocated for StringPtr after it has been used.
|
|
//
|
|
gBS->FreePool (StringPtr);
|
|
|
|
for (Index = 0; FormTags.Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {
|
|
GrayOut = FALSE;
|
|
Suppress = FALSE;
|
|
SuppressIf = FALSE;
|
|
Conditional = FALSE;
|
|
FileFormTags = FileFormTagsHead;
|
|
|
|
if (FormTags.Tags[Index].Operand == EFI_IFR_FORM_OP) {
|
|
FormId = FormTags.Tags[Index].Id;
|
|
}
|
|
//
|
|
// This gives us visibility to the FileFormTags->NvRamMap to check things
|
|
// ActiveIfr is a global maintained by the menuing code to ensure that we
|
|
// are pointing to the correct formset's file data.
|
|
//
|
|
for (Count = 0; Count < gActiveIfr; Count++) {
|
|
FileFormTags = FileFormTags->NextFile;
|
|
}
|
|
//
|
|
// GrayoutIf [SuppressIf]
|
|
// <BOOLEANS>
|
|
// OpCode(s)
|
|
// EndIf
|
|
//
|
|
// SuppressIf [GrayoutIf]
|
|
// <BOOLEANS>
|
|
// OpCode(s)
|
|
// EndIf
|
|
//
|
|
Count = 0;
|
|
|
|
do {
|
|
switch (FormTags.Tags[Index].Operand) {
|
|
case EFI_IFR_SUPPRESS_IF_OP:
|
|
SuppressIf = TRUE;
|
|
|
|
case EFI_IFR_GRAYOUT_IF_OP:
|
|
|
|
Conditional = TRUE;
|
|
|
|
//
|
|
// Advance to the next op-code
|
|
//
|
|
Index++;
|
|
|
|
//
|
|
// We are now pointing to the beginning of the consistency checking. Let's fast forward
|
|
// through the AND/OR/NOT data to come up with some meaningful ID data.
|
|
//
|
|
for (;
|
|
FormTags.Tags[Index].Operand == EFI_IFR_AND_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_OR_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_GT_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_GE_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP;
|
|
Index++
|
|
)
|
|
;
|
|
|
|
//
|
|
// We need to walk through the consistency checks until we hit the end of the consistency
|
|
// FALSE means evaluate this single expression
|
|
// The ConsistencyId refers to which expression in the Consistency database to use
|
|
//
|
|
if (SuppressIf) {
|
|
Suppress = ValueIsNotValid (
|
|
FALSE,
|
|
FormTags.Tags[Index].ConsistencyId,
|
|
&FormTags.Tags[Index],
|
|
FileFormTags,
|
|
&String
|
|
);
|
|
SuppressIf = FALSE;
|
|
} else {
|
|
GrayOut = ValueIsNotValid (
|
|
FALSE,
|
|
FormTags.Tags[Index].ConsistencyId,
|
|
&FormTags.Tags[Index],
|
|
FileFormTags,
|
|
&String
|
|
);
|
|
}
|
|
//
|
|
// Advance to the end of the expression (Will land us at a grayoutif/suppressif or the op-code being affected)
|
|
//
|
|
for (;
|
|
FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_VAL_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_EQ_VAR_VAL_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_ID_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_LIST_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_AND_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_OR_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_TRUE_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_FALSE_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_GT_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_GE_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_LABEL_OP;
|
|
Index++
|
|
)
|
|
;
|
|
break;
|
|
|
|
default:
|
|
goto GetOut;
|
|
}
|
|
//
|
|
// Do this two times (at most will see a suppress and grayout combination
|
|
//
|
|
Count++;
|
|
} while (Count < 2);
|
|
|
|
GetOut:
|
|
do {
|
|
if (GrayOut) {
|
|
FormTags.Tags[Index].GrayOut = TRUE;
|
|
} else {
|
|
FormTags.Tags[Index].GrayOut = FALSE;
|
|
}
|
|
if (Suppress && FormTags.Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
|
|
//
|
|
// Only need .Suppress field when the tag is a one_of_option. For other cases, omit them directly.
|
|
//
|
|
FormTags.Tags[Index].Suppress = TRUE;
|
|
} else {
|
|
FormTags.Tags[Index].Suppress = FALSE;
|
|
}
|
|
|
|
if ((
|
|
FormTags.Tags[Index].NumberOfLines > 0 ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_DATE_OP ||
|
|
FormTags.Tags[Index].Operand == EFI_IFR_TIME_OP
|
|
) &&
|
|
!Suppress
|
|
) {
|
|
|
|
StringPtr = GetToken (FormTags.Tags[Index].Text, Handle);
|
|
|
|
Width = GetWidth (&FormTags.Tags[Index], Handle);
|
|
|
|
//
|
|
// This data can be retrieved over and over again. Therefore, reset to original values
|
|
// before processing otherwise things will start growing linearly
|
|
//
|
|
if (FormTags.Tags[Index].NumberOfLines > 1) {
|
|
FormTags.Tags[Index].NumberOfLines = 1;
|
|
}
|
|
|
|
for (Count = 0; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) {
|
|
//
|
|
// If there is more string to process print on the next row and increment the Skip value
|
|
//
|
|
if (StrLen (&StringPtr[ArrayEntry])) {
|
|
FormTags.Tags[Index].NumberOfLines++;
|
|
}
|
|
|
|
gBS->FreePool (OutputString);
|
|
}
|
|
|
|
ArrayEntry = 0;
|
|
|
|
//
|
|
// We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
|
|
// it in UiFreeMenu.
|
|
//
|
|
UiAddSubMenuOption (StringPtr, Handle, FormTags.Tags, Index, FormId, MenuItemCount);
|
|
MenuItemCount++;
|
|
}
|
|
//
|
|
// Keep processing menu entries based on the resultant suppress/grayout results until we hit an end-if
|
|
//
|
|
Index++;
|
|
} while (FormTags.Tags[Index].Operand != EFI_IFR_END_IF_OP && Conditional);
|
|
|
|
//
|
|
// We advanced the index for the above conditional, rewind it to keep harmony with the for loop logic
|
|
//
|
|
Index--;
|
|
}
|
|
|
|
Selection = UiDisplayMenu (TRUE, FileFormTagsHead, (EFI_IFR_DATA_ARRAY *) CallbackData);
|
|
|
|
return Selection;
|
|
}
|
|
|
|
VOID
|
|
InitializeBrowserStrings (
|
|
VOID
|
|
)
|
|
{
|
|
gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle);
|
|
gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle);
|
|
gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);
|
|
gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);
|
|
gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle);
|
|
gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle);
|
|
gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle);
|
|
gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle);
|
|
gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle);
|
|
gNumericInput = GetToken (STRING_TOKEN (NUMERIC_INPUT), gHiiHandle);
|
|
gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle);
|
|
gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);
|
|
gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);
|
|
gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);
|
|
gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);
|
|
gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);
|
|
gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
|
|
gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle);
|
|
gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
|
|
gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
|
|
gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
|
|
gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle);
|
|
gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle);
|
|
gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle);
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
UpdateKeyHelp (
|
|
IN UI_MENU_OPTION *Selection,
|
|
IN BOOLEAN Selected
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Update key's help imformation
|
|
|
|
Arguments:
|
|
Selection C The form that current display
|
|
Selected C Whether or not a tag be selected
|
|
|
|
Returns:
|
|
None
|
|
--*/
|
|
{
|
|
UINTN SecCol;
|
|
UINTN ThdCol;
|
|
UINTN LeftColumnOfHelp;
|
|
UINTN RightColumnOfHelp;
|
|
UINTN TopRowOfHelp;
|
|
UINTN BottomRowOfHelp;
|
|
UINTN StartColumnOfHelp;
|
|
EFI_SCREEN_DESCRIPTOR LocalScreen;
|
|
|
|
CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
|
|
SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
|
|
ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3;
|
|
|
|
StartColumnOfHelp = LocalScreen.LeftColumn + 2;
|
|
LeftColumnOfHelp = LocalScreen.LeftColumn + 1;
|
|
RightColumnOfHelp = LocalScreen.RightColumn - 2;
|
|
TopRowOfHelp = LocalScreen.BottomRow - 4;
|
|
BottomRowOfHelp = LocalScreen.BottomRow - 3;
|
|
|
|
if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) {
|
|
return ;
|
|
}
|
|
|
|
gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
|
|
|
|
switch (Selection->ThisTag->Operand) {
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
case EFI_IFR_ONE_OF_OP:
|
|
case EFI_IFR_NUMERIC_OP:
|
|
case EFI_IFR_TIME_OP:
|
|
case EFI_IFR_DATE_OP:
|
|
ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
|
|
|
|
if (!Selected) {
|
|
if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
|
|
PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
|
|
PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
|
|
PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
|
|
PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
|
|
|
|
}
|
|
|
|
if ((Selection->ThisTag->Operand == EFI_IFR_DATE_OP) || (Selection->ThisTag->Operand == EFI_IFR_TIME_OP)) {
|
|
PrintAt (
|
|
StartColumnOfHelp,
|
|
BottomRowOfHelp,
|
|
(CHAR16 *) L"%c%c%c%c%s",
|
|
ARROW_UP,
|
|
ARROW_DOWN,
|
|
ARROW_RIGHT,
|
|
ARROW_LEFT,
|
|
gMoveHighlight
|
|
);
|
|
PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber);
|
|
} else {
|
|
PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
|
|
PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
|
|
}
|
|
} else {
|
|
PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);
|
|
|
|
//
|
|
// If it is a selected numeric with manual input, display different message
|
|
//
|
|
if ((Selection->ThisTag->Operand == EFI_IFR_NUMERIC_OP) && (Selection->ThisTag->Step == 0)) {
|
|
PrintStringAt (SecCol, TopRowOfHelp, gNumericInput);
|
|
} else if (Selection->ThisTag->Operand != EFI_IFR_ORDERED_LIST_OP) {
|
|
PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
|
|
}
|
|
|
|
if (Selection->ThisTag->Operand == EFI_IFR_ORDERED_LIST_OP) {
|
|
PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);
|
|
PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);
|
|
}
|
|
|
|
PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
|
|
|
|
if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
|
|
PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
|
|
PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
|
|
PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
|
|
PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
|
|
}
|
|
|
|
PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
|
|
PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);
|
|
break;
|
|
|
|
case EFI_IFR_REF_OP:
|
|
case EFI_IFR_PASSWORD_OP:
|
|
case EFI_IFR_STRING_OP:
|
|
ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
|
|
|
|
if (!Selected) {
|
|
if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
|
|
PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
|
|
PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
|
|
PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
|
|
PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
|
|
}
|
|
|
|
PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
|
|
PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
|
|
} else {
|
|
if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) {
|
|
PrintStringAt (
|
|
(LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2,
|
|
BottomRowOfHelp,
|
|
gEnterCommitString
|
|
);
|
|
PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
ExtractFormHandle (
|
|
IN UI_MENU_OPTION *Selection,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINTN IdValue,
|
|
OUT UINT16 *FormHandle,
|
|
OUT UINT16 *TitleToken,
|
|
OUT EFI_FORM_TAGS *FormTags
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_FILE_FORM_TAGS *FileFormTags;
|
|
EFI_FORM_TAGS LocalTags;
|
|
|
|
FileFormTags = FileFormTagsHead;
|
|
|
|
//
|
|
// Advance FileFormTags to the correct file's tag information.
|
|
// For instance, if Selection->IfrNumber is 3, that means the 4th
|
|
// file (0-based) in the FileFormTags linked-list contains the tag
|
|
// information.
|
|
//
|
|
for (Index = 0; Index < Selection->IfrNumber; Index++) {
|
|
FileFormTags = FileFormTags->NextFile;
|
|
}
|
|
|
|
LocalTags = FileFormTags->FormTags;
|
|
|
|
if (IdValue == 0) {
|
|
//
|
|
// Advance Index to the first FormOp tag information
|
|
//
|
|
for (Index = 0; FileFormTags->FormTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
|
|
;
|
|
} else {
|
|
//
|
|
// Advance Index to the FormOp with the correct ID value
|
|
//
|
|
for (; LocalTags.Next != NULL; LocalTags = *LocalTags.Next) {
|
|
for (Index = 0; LocalTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
|
|
;
|
|
if (LocalTags.Tags[Index].Id == IdValue) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// return the Form Id, Text, and the File's FormTags structure
|
|
//
|
|
*FormHandle = LocalTags.Tags[Index].Id;
|
|
*TitleToken = LocalTags.Tags[Index].Text;
|
|
*FormTags = LocalTags;
|
|
return ;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UpdateNewTagData (
|
|
IN UINT8 *FormData,
|
|
IN UINT16 ConsistencyId,
|
|
IN UINT16 CurrentVariable,
|
|
IN EFI_FORM_TAGS *FormTags,
|
|
OUT EFI_FILE_FORM_TAGS *FileFormTags
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 Index;
|
|
UINT16 QuestionIndex;
|
|
UINT16 NumberOfTags;
|
|
INT16 CurrTag;
|
|
UINT8 TagLength;
|
|
UINTN Count;
|
|
BOOLEAN Finished;
|
|
|
|
//
|
|
// Initialize some Index variable and Status
|
|
//
|
|
Count = 0;
|
|
QuestionIndex = 0;
|
|
NumberOfTags = 1;
|
|
Index = 0;
|
|
Status = EFI_SUCCESS;
|
|
Finished = FALSE;
|
|
|
|
//
|
|
// Determine the number of tags for the first form
|
|
//
|
|
GetTagCount (&FormData[Index], &NumberOfTags);
|
|
|
|
//
|
|
// Allocate memory for our tags on the first form
|
|
//
|
|
FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG));
|
|
ASSERT (FormTags->Tags != NULL);
|
|
|
|
for (CurrTag = 0; FormData[Index] != EFI_IFR_END_FORM_SET_OP; CurrTag++) {
|
|
//
|
|
// Operand = IFR OpCode
|
|
//
|
|
FormTags->Tags[CurrTag].Operand = FormData[Index];
|
|
|
|
//
|
|
// Assume for now 0 lines occupied by this OpCode
|
|
//
|
|
FormTags->Tags[CurrTag].NumberOfLines = 0;
|
|
|
|
//
|
|
// Determine the length of the Tag so we can later skip to the next tag in the form
|
|
//
|
|
//
|
|
// get the length
|
|
//
|
|
TagLength = FormData[Index + 1];
|
|
//
|
|
// Operate on the Found OpCode
|
|
//
|
|
switch (FormData[Index]) {
|
|
|
|
case EFI_IFR_FORM_OP:
|
|
case EFI_IFR_SUBTITLE_OP:
|
|
case EFI_IFR_TEXT_OP:
|
|
case EFI_IFR_REF_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_SELECT_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) &FormData[Index])->VarId, sizeof (UINT16));
|
|
break;
|
|
|
|
case EFI_IFR_END_FORM_OP:
|
|
FormTags->Tags[CurrTag].Operand = FormData[Index];
|
|
FormTags->Tags[CurrTag].NumberOfLines = 0;
|
|
|
|
Finished = TRUE;
|
|
break;
|
|
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
case EFI_IFR_ONE_OF_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
|
|
|
|
//
|
|
// Store away the CurrTag since what follows will be the answer that we
|
|
// need to place into the appropriate location in the tag array
|
|
//
|
|
//
|
|
// record for setting default later
|
|
//
|
|
QuestionIndex = (UINT16) CurrTag;
|
|
break;
|
|
|
|
case EFI_IFR_ONE_OF_OPTION_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
FormTags->Tags[QuestionIndex].Key = ((EFI_IFR_ONE_OF_OPTION *) &FormData[Index])->Key;
|
|
FormTags->Tags[QuestionIndex].ResetRequired = (BOOLEAN) (FormTags->Tags[QuestionIndex].Flags & EFI_IFR_FLAG_RESET_REQUIRED);
|
|
break;
|
|
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_OP:
|
|
GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_DATE_OP:
|
|
//
|
|
// Date elements come in as a Year, Month, Day. We need to process them as a country-based
|
|
// Order. It is much easier to do it here than anywhere else.
|
|
//
|
|
// For US standards - we want Month/Day/Year, thus we advance "i" +1, +2, +0 while CurrTag is +0, +1, +2
|
|
//
|
|
GetNumericHeader (
|
|
&FormTags->Tags[CurrTag],
|
|
FormData,
|
|
(UINT16) (Index + TagLength),
|
|
(UINT16) 0,
|
|
FileFormTags,
|
|
CurrentVariable
|
|
);
|
|
|
|
//
|
|
// The current language selected + the Date operand
|
|
//
|
|
FormTags->Tags[CurrTag + 1].Operand = FormData[Index];
|
|
GetNumericHeader (
|
|
&FormTags->Tags[CurrTag + 1],
|
|
FormData,
|
|
(UINT16) (Index + TagLength + FormData[Index + TagLength + 1]),
|
|
(UINT16) 0,
|
|
FileFormTags,
|
|
CurrentVariable
|
|
);
|
|
|
|
//
|
|
// The current language selected + the Date operand
|
|
//
|
|
FormTags->Tags[CurrTag + 2].Operand = FormData[Index];
|
|
GetNumericHeader (&FormTags->Tags[CurrTag + 2], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable);
|
|
|
|
CurrTag = (INT16) (CurrTag + 2);
|
|
|
|
Index = (UINT16) (Index + TagLength);
|
|
//
|
|
// get the length
|
|
//
|
|
TagLength = FormData[Index + 1];
|
|
Index = (UINT16) (Index + TagLength);
|
|
//
|
|
// get the length
|
|
//
|
|
TagLength = FormData[Index + 1];
|
|
break;
|
|
|
|
case EFI_IFR_TIME_OP:
|
|
GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 0, FileFormTags, CurrentVariable);
|
|
|
|
if (Count == 2) {
|
|
//
|
|
// Override the GetQuestionHeader information - date/time are treated very differently
|
|
//
|
|
FormTags->Tags[CurrTag].NumberOfLines = 1;
|
|
Count = 0;
|
|
} else {
|
|
//
|
|
// The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines
|
|
// associated with them, and the third has 1 line to allow to space beyond the choice.
|
|
//
|
|
Count++;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_PASSWORD_OP:
|
|
case EFI_IFR_STRING_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_INCONSISTENT_IF_OP:
|
|
case EFI_IFR_SUPPRESS_IF_OP:
|
|
case EFI_IFR_GRAYOUT_IF_OP:
|
|
ConsistencyId++;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_VAL_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_VAR_VAL_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_ID_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
|
|
break;
|
|
|
|
case EFI_IFR_AND_OP:
|
|
case EFI_IFR_OR_OP:
|
|
case EFI_IFR_NOT_OP:
|
|
case EFI_IFR_TRUE_OP:
|
|
case EFI_IFR_FALSE_OP:
|
|
case EFI_IFR_GT_OP:
|
|
case EFI_IFR_GE_OP:
|
|
FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_LIST_OP:
|
|
IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
|
|
|
|
FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
//
|
|
// End of switch
|
|
//
|
|
if (Finished) {
|
|
break;
|
|
}
|
|
//
|
|
// Per spec., we ignore ops that we don't know how to deal with. Skip to next tag
|
|
//
|
|
Index = (UINT16) (Index + TagLength);
|
|
}
|
|
//
|
|
// End of Index
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
ExtractDynamicFormHandle (
|
|
IN UI_MENU_OPTION *Selection,
|
|
IN UINT8 *CallbackData,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINTN IdValue,
|
|
OUT UINT16 *FormHandle,
|
|
OUT UINT16 *TitleToken,
|
|
OUT EFI_FORM_TAGS *FormTags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function does the most of the works when the EFI_TAG that
|
|
user selects on is EFI_IFR_FLAG_INTERACTIVE or EFI_IFR_PASSWORD_OP:
|
|
invoke CallBack, update the new form data.
|
|
|
|
Arguments:
|
|
|
|
Selection - The current selection of the form.
|
|
CallbackData - The pointer to host the data passed back by the callback function.
|
|
FileFormTagsHead - Prompt string token of the one-of box
|
|
IdValue - The current page number.
|
|
FormHandle - Output the the handle of the form.
|
|
TitleToken - Output the TitleToken of the new page.
|
|
FormTags - Output the FormFags of the new page.
|
|
|
|
Returns:
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
UINTN Index;
|
|
UINTN BackupIndex;
|
|
EFI_FILE_FORM_TAGS *FileFormTags;
|
|
EFI_FORM_TAGS *LocalTags;
|
|
EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
|
|
EFI_STATUS Status;
|
|
UINTN Length;
|
|
UINT8 *Buffer;
|
|
EFI_PHYSICAL_ADDRESS CallbackHandle;
|
|
EFI_GUID TagGuid;
|
|
UINT16 TargetPage;
|
|
EFI_HII_CALLBACK_PACKET *Packet;
|
|
UINTN ScreenSize;
|
|
CHAR16 NullCharacter;
|
|
EFI_INPUT_KEY Key;
|
|
UINT16 ConsistencyId;
|
|
UINT16 CurrentVariable;
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
EFI_IFR_DATA_ENTRY *DataEntry;
|
|
|
|
VariableDefinition = NULL;
|
|
NullCharacter = CHAR_NULL;
|
|
|
|
CurrentVariable = 0;
|
|
FileFormTags = FileFormTagsHead;
|
|
Length = 0;
|
|
CallbackHandle = 0;
|
|
TargetPage = (UINT16) IdValue;
|
|
Packet = NULL;
|
|
ConsistencyId = 0;
|
|
|
|
//
|
|
// Advance FileFormTags to the correct file's tag information.
|
|
// For instance, if Selection->IfrNumber is 3, that means the 4th
|
|
// file (0-based) in the FileFormTags linked-list contains the tag
|
|
// information.
|
|
//
|
|
for (Index = 0; Index < Selection->IfrNumber; Index++) {
|
|
FileFormTags = FileFormTags->NextFile;
|
|
}
|
|
|
|
LocalTags = &FileFormTags->FormTags;
|
|
|
|
//
|
|
// Advance Index to the FormOp with the correct ID value
|
|
//
|
|
for (; LocalTags->Next != NULL; LocalTags = LocalTags->Next) {
|
|
if ((LocalTags->Tags[0].CallbackHandle != 0) && (CallbackHandle == 0)) {
|
|
CallbackHandle = LocalTags->Tags[0].CallbackHandle;
|
|
CopyMem (&TagGuid, &LocalTags->Tags[0].GuidValue, sizeof (EFI_GUID));
|
|
}
|
|
|
|
for (Index = 0; LocalTags->Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
|
|
;
|
|
if (LocalTags->Tags[Index].Id == IdValue) {
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// If we are going to callback on a non-goto opcode, make sure we don't change pages
|
|
//
|
|
if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) {
|
|
TargetPage = Selection->FormId;
|
|
}
|
|
//
|
|
// The first tag below should be the form op-code. We need to store away the
|
|
// current variable setting to ensure if we have to reload the page, that we
|
|
// can correctly restore the values for the active variable
|
|
//
|
|
CurrentVariable = Selection->Tags[0].VariableNumber;
|
|
|
|
//
|
|
// Remember that dynamic pages in an environment where all pages are not
|
|
// dynamic require us to call back to the user to give them an opportunity
|
|
// to register fresh information in the HII database so that we can extract it.
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
(VOID *) (UINTN) CallbackHandle,
|
|
&gEfiFormCallbackProtocolGuid,
|
|
(VOID **) &FormCallback
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (LocalTags->Tags);
|
|
return ;
|
|
}
|
|
|
|
ExtractRequestedNvMap (FileFormTags, CurrentVariable, &VariableDefinition);
|
|
|
|
if (Selection->ThisTag->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS)) {
|
|
((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = VariableDefinition->NvRamMap;
|
|
} else {
|
|
((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = NULL;
|
|
}
|
|
|
|
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
|
|
Status = FormCallback->Callback (
|
|
FormCallback,
|
|
Selection->ThisTag->Key,
|
|
(EFI_IFR_DATA_ARRAY *) CallbackData,
|
|
&Packet
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Restore Previous Value
|
|
//
|
|
CopyMem (
|
|
&VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart],
|
|
gPreviousValue,
|
|
Selection->ThisTag->StorageWidth
|
|
);
|
|
|
|
if (Packet != NULL) {
|
|
//
|
|
// Upon error, we will likely receive a string to print out
|
|
//
|
|
ScreenSize = GetStringWidth (Packet->String) / 2;
|
|
|
|
//
|
|
// Display error popup
|
|
//
|
|
CreatePopUp (ScreenSize, 3, &NullCharacter, Packet->String, &NullCharacter);
|
|
|
|
do {
|
|
Status = WaitForKeyStroke (&Key);
|
|
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
|
|
} else {
|
|
UpdateStatusBar (INPUT_ERROR, (UINT8) 0, TRUE);
|
|
}
|
|
|
|
} else {
|
|
if (Packet != NULL) {
|
|
//
|
|
// We need to on a non-error, look in the outbound Packet for information and update the NVRAM
|
|
// location associated with the op-code specified there. This is used on single op-code instances
|
|
// and not for when a hyperlink sent us a whole page of data.
|
|
//
|
|
DataEntry = (EFI_IFR_DATA_ENTRY *) (&Packet->DataArray + 1);
|
|
if (Packet->DataArray.EntryCount == 1) {
|
|
switch (DataEntry->OpCode) {
|
|
case EFI_IFR_STRING_OP:
|
|
case EFI_IFR_NUMERIC_OP:
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
case EFI_IFR_ONE_OF_OP:
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
CopyMem (
|
|
&VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart],
|
|
&DataEntry->Data,
|
|
Selection->ThisTag->StorageWidth
|
|
);
|
|
break;
|
|
|
|
case EFI_IFR_NV_ACCESS_COMMAND:
|
|
CopyMem (
|
|
&VariableDefinition->NvRamMap[((EFI_IFR_NV_DATA *) Packet)->QuestionId],
|
|
((EFI_IFR_NV_DATA *) Packet) + 1,
|
|
((EFI_IFR_NV_DATA *) Packet)->StorageWidth
|
|
);
|
|
break;
|
|
|
|
}
|
|
|
|
if (DataEntry->Flags & RESET_REQUIRED) {
|
|
gResetRequired = TRUE;
|
|
}
|
|
|
|
if (DataEntry->Flags & EXIT_REQUIRED) {
|
|
gExitRequired = TRUE;
|
|
}
|
|
|
|
if (DataEntry->Flags & SAVE_REQUIRED) {
|
|
gSaveRequired = TRUE;
|
|
}
|
|
|
|
if (DataEntry->Flags & NV_CHANGED) {
|
|
gNvUpdateRequired = TRUE;
|
|
}
|
|
|
|
if (DataEntry->Flags & NV_NOT_CHANGED) {
|
|
gNvUpdateRequired = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Packet != NULL) {
|
|
gBS->FreePool (Packet);
|
|
}
|
|
|
|
for (BackupIndex = 0; LocalTags->Tags[BackupIndex].Operand != EFI_IFR_END_FORM_OP; BackupIndex++) {
|
|
switch (LocalTags->Tags[BackupIndex].Operand) {
|
|
case EFI_IFR_EQ_VAR_VAL_OP:
|
|
case EFI_IFR_EQ_ID_VAL_OP:
|
|
case EFI_IFR_EQ_ID_ID_OP:
|
|
case EFI_IFR_AND_OP:
|
|
case EFI_IFR_OR_OP:
|
|
case EFI_IFR_NOT_OP:
|
|
case EFI_IFR_TRUE_OP:
|
|
case EFI_IFR_FALSE_OP:
|
|
case EFI_IFR_GT_OP:
|
|
case EFI_IFR_GE_OP:
|
|
case EFI_IFR_EQ_ID_LIST_OP:
|
|
//
|
|
// If we encountered a ConsistencyId value, on this page they will be incremental
|
|
// So register the first value we encounter. We will pass this in when we re-create this page
|
|
//
|
|
if ((LocalTags->Tags[BackupIndex].ConsistencyId != 0) && (ConsistencyId == 0)) {
|
|
ConsistencyId = (UINT16) (LocalTags->Tags[BackupIndex].ConsistencyId - 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Delete the buffer associated with previous dynamic page
|
|
// We will re-allocate a buffer....
|
|
//
|
|
gBS->FreePool (LocalTags->Tags);
|
|
|
|
Length = 0xF000;
|
|
Buffer = AllocateZeroPool (Length);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
//
|
|
// Get the form that was updated by the callback
|
|
//
|
|
Hii->GetForms (
|
|
Hii,
|
|
Selection->Handle,
|
|
TargetPage,
|
|
&Length,
|
|
Buffer
|
|
);
|
|
|
|
//
|
|
// Ok, we have the new page.....now we must purge the old page and re-allocate
|
|
// the tag page with the new data
|
|
//
|
|
UpdateNewTagData (
|
|
Buffer,
|
|
ConsistencyId,
|
|
CurrentVariable,
|
|
LocalTags,
|
|
FileFormTags
|
|
);
|
|
|
|
//
|
|
// return the Form Id, Text, and the File's FormTags structure
|
|
//
|
|
*FormHandle = LocalTags->Tags[0].Id;
|
|
*TitleToken = LocalTags->Tags[0].Text;
|
|
*FormTags = *LocalTags;
|
|
|
|
FormTags->Tags[0].CallbackHandle = CallbackHandle;
|
|
CopyMem (&FormTags->Tags[0].GuidValue, &TagGuid, sizeof (EFI_GUID));
|
|
|
|
return ;
|
|
}
|
|
|
|
UI_MENU_OPTION *
|
|
SetupBrowser (
|
|
IN UI_MENU_OPTION *Selection,
|
|
IN BOOLEAN Callback,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINT8 *CallbackData
|
|
)
|
|
{
|
|
UINT16 FormHandle;
|
|
UINT16 TitleToken;
|
|
EFI_FORM_TAGS FormTags;
|
|
|
|
gEntryNumber = -1;
|
|
gLastOpr = FALSE;
|
|
//
|
|
// Displays the Header and Footer borders
|
|
//
|
|
DisplayPageFrame ();
|
|
|
|
//
|
|
// Id of 0 yields the getting of the top form whatever the ID is. Usually the first form in the IFR
|
|
//
|
|
ExtractFormHandle (Selection, FileFormTagsHead, 0, &FormHandle, &TitleToken, &FormTags);
|
|
|
|
Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData);
|
|
|
|
//
|
|
// If selection is null use the former selection
|
|
//
|
|
if (Selection == NULL) {
|
|
return Selection;
|
|
}
|
|
|
|
if (Callback) {
|
|
return Selection;
|
|
}
|
|
|
|
while (Selection->Tags != NULL) {
|
|
if (Selection->Previous) {
|
|
ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags);
|
|
} else {
|
|
//
|
|
// True if a hyperlink/jump is selected
|
|
//
|
|
if (Selection->ThisTag->Operand == EFI_IFR_REF_OP && Selection->ThisTag->Id != 0x0000) {
|
|
if (Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
|
|
ExtractDynamicFormHandle (
|
|
Selection,
|
|
CallbackData,
|
|
FileFormTagsHead,
|
|
Selection->ThisTag->Id,
|
|
&FormHandle,
|
|
&TitleToken,
|
|
&FormTags
|
|
);
|
|
goto DisplayPage;
|
|
} else {
|
|
ExtractFormHandle (Selection, FileFormTagsHead, Selection->ThisTag->Id, &FormHandle, &TitleToken, &FormTags);
|
|
goto DisplayPage;
|
|
}
|
|
}
|
|
|
|
if ((Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) &&
|
|
(Selection->ThisTag->Operand != EFI_IFR_PASSWORD_OP)
|
|
) {
|
|
ExtractDynamicFormHandle (
|
|
Selection,
|
|
CallbackData,
|
|
FileFormTagsHead,
|
|
Selection->FormId,
|
|
&FormHandle,
|
|
&TitleToken,
|
|
&FormTags
|
|
);
|
|
} else {
|
|
ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags);
|
|
}
|
|
}
|
|
|
|
DisplayPage:
|
|
//
|
|
// Displays the Header and Footer borders
|
|
//
|
|
DisplayPageFrame ();
|
|
|
|
Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData);
|
|
|
|
if (Selection == NULL) {
|
|
break;
|
|
}
|
|
};
|
|
|
|
return Selection;
|
|
}
|