/** @file | |
Implementation for Hii Popup Protocol. | |
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "FormDisplay.h" | |
EFI_SCREEN_DESCRIPTOR gPopupDimensions; | |
LIST_ENTRY gUserSelectableOptions; | |
EFI_STRING gMessageString; | |
UINTN gMesStrLineNum; | |
UINTN gMaxRowWidth; | |
/** | |
Free the user selectable option structure data. | |
@param OptionList Point to the selectable option list which need to be freed. | |
**/ | |
VOID | |
FreeSelectableOptions ( | |
LIST_ENTRY *OptionList | |
) | |
{ | |
LIST_ENTRY *Link; | |
USER_SELECTABLE_OPTION *SelectableOption; | |
while (!IsListEmpty (OptionList)) { | |
Link = GetFirstNode (OptionList); | |
SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link); | |
RemoveEntryList (&SelectableOption->Link); | |
FreePool (SelectableOption); | |
} | |
} | |
/** | |
Display one selectable option. | |
@param SelectableOption The selectable option need to be drew. | |
@param Highlight Whether the option need to be highlighted. | |
**/ | |
VOID | |
DisplayOneSelectableOption ( | |
IN USER_SELECTABLE_OPTION *SelectableOption, | |
IN BOOLEAN Highlight | |
) | |
{ | |
if (Highlight) { | |
gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ()); | |
} | |
PrintStringAt (SelectableOption->OptionCol, SelectableOption->OptionRow, SelectableOption->OptionString); | |
gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); | |
} | |
/** | |
Add one selectable option to option list. This is the work function for AddUserSelectableOptions. | |
@param PopupType The option need to be drew. | |
@param OptionType The type of this selection option. | |
@param OptionString Point to the option string that to be shown. | |
@param OptionCol The column that the option need to be drew at. | |
@param OptionRow The row that the option need to be drew at. | |
@retval EFI_SUCCESS This function implement successfully. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resources available. | |
**/ | |
EFI_STATUS | |
AddOneSelectableOption ( | |
IN EFI_HII_POPUP_TYPE PopupType, | |
IN EFI_HII_POPUP_SELECTION OptionType, | |
IN CHAR16 *OptionString, | |
IN UINTN OptionCol, | |
IN UINTN OptionRow | |
) | |
{ | |
USER_SELECTABLE_OPTION *UserSelectableOption; | |
UserSelectableOption = AllocateZeroPool (sizeof (USER_SELECTABLE_OPTION)); | |
if (UserSelectableOption == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Initialize the user selectable option based on the PopupType and OptionType. | |
// And then add the option to the option list gUserSelectableOptions. | |
// | |
UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE; | |
UserSelectableOption->OptionString = OptionString; | |
UserSelectableOption->OptionType = OptionType; | |
UserSelectableOption->OptionCol = OptionCol; | |
UserSelectableOption->OptionRow = OptionRow; | |
UserSelectableOption->MinSequence = 0; | |
switch (PopupType) { | |
case EfiHiiPopupTypeOk: | |
UserSelectableOption->MaxSequence = 0; | |
UserSelectableOption->Sequence = 0; | |
break; | |
case EfiHiiPopupTypeOkCancel: | |
UserSelectableOption->MaxSequence = 1; | |
if (OptionType == EfiHiiPopupSelectionOk) { | |
UserSelectableOption->Sequence = 0; | |
} else { | |
UserSelectableOption->Sequence = 1; | |
} | |
break; | |
case EfiHiiPopupTypeYesNo: | |
UserSelectableOption->MaxSequence = 1; | |
if (OptionType == EfiHiiPopupSelectionYes) { | |
UserSelectableOption->Sequence = 0; | |
} else { | |
UserSelectableOption->Sequence = 1; | |
} | |
break; | |
case EfiHiiPopupTypeYesNoCancel: | |
UserSelectableOption->MaxSequence = 2; | |
if (OptionType == EfiHiiPopupSelectionYes) { | |
UserSelectableOption->Sequence = 0; | |
} else if (OptionType == EfiHiiPopupSelectionNo) { | |
UserSelectableOption->Sequence = 1; | |
} else { | |
UserSelectableOption->Sequence = 2; | |
} | |
break; | |
default: | |
break; | |
} | |
InsertTailList (&gUserSelectableOptions, &UserSelectableOption->Link); | |
return EFI_SUCCESS; | |
} | |
/** | |
Add user selectable options to option list for different types of Popup. | |
@param PopupType Type of the popup to display. | |
@retval EFI_SUCCESS This function implement successfully. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resources available. | |
**/ | |
EFI_STATUS | |
AddUserSelectableOptions ( | |
IN EFI_HII_POPUP_TYPE PopupType | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN EndCol; | |
UINTN StartCol; | |
UINTN OptionCol; | |
UINTN OptionRow; | |
UINTN ColDimension; | |
Status = EFI_SUCCESS; | |
EndCol = gPopupDimensions.RightColumn; | |
StartCol = gPopupDimensions.LeftColumn; | |
OptionRow = gPopupDimensions.BottomRow - POPUP_BORDER; | |
ColDimension = EndCol - StartCol + 1; | |
InitializeListHead (&gUserSelectableOptions); | |
switch (PopupType) { | |
case EfiHiiPopupTypeOk: | |
// | |
// Add [Ok] option to the option list. | |
// | |
OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_WIDTH) / 2; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow); | |
break; | |
case EfiHiiPopupTypeOkCancel: | |
// | |
// Add [Ok] and [Cancel] options to the option list. | |
// | |
OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow); | |
OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3 - (GetStringWidth (gCancelOption) -2) / 2 + 1; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow); | |
break; | |
case EfiHiiPopupTypeYesNo: | |
// | |
// Add [Yes] and [No] options to the option list. | |
// | |
OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow); | |
OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3 - (GetStringWidth (gNoOption)- 2) / 2 + 1; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow); | |
break; | |
case EfiHiiPopupTypeYesNoCancel: | |
// | |
// Add [Yes], [No] and [Cancel] options to the option list. | |
// | |
OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow); | |
OptionCol = StartCol + (ColDimension - (GetStringWidth (gNoOption) -2) / 2) / 2; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow); | |
OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4 - (GetStringWidth (gCancelOption) - 2) / 2 + 1; | |
Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow); | |
break; | |
default: | |
break; | |
} | |
return Status; | |
} | |
/** | |
Show selectable options to user and get the one that user select. | |
@param PopupType Type of the popup to display. | |
@param UserSelection User selection. | |
**/ | |
VOID | |
GetUserSelection ( | |
IN EFI_HII_POPUP_TYPE PopupType, | |
OUT EFI_HII_POPUP_SELECTION *UserSelection | |
) | |
{ | |
LIST_ENTRY *HighlightPos; | |
LIST_ENTRY *Link; | |
USER_SELECTABLE_OPTION *SelectableOption; | |
USER_SELECTABLE_OPTION *HighlightOption; | |
EFI_INPUT_KEY KeyValue; | |
EFI_STATUS Status; | |
// | |
// Display user selectable options in gUserSelectableOptions and get the option which user selects. | |
// | |
HighlightPos = gUserSelectableOptions.ForwardLink; | |
do { | |
for (Link = gUserSelectableOptions.ForwardLink; Link != &gUserSelectableOptions; Link = Link->ForwardLink) { | |
SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link); | |
DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos)); | |
} | |
// | |
// If UserSelection is NULL, there is no need to handle the key user input, just return. | |
// | |
if (UserSelection == NULL) { | |
return; | |
} | |
Status = WaitForKeyStroke (&KeyValue); | |
ASSERT_EFI_ERROR (Status); | |
HighlightOption = SELECTABLE_OPTION_FROM_LINK (HighlightPos); | |
switch (KeyValue.UnicodeChar) { | |
case CHAR_NULL: | |
switch (KeyValue.ScanCode) { | |
case SCAN_RIGHT: | |
if (HighlightOption->Sequence < HighlightOption->MaxSequence) { | |
HighlightPos = HighlightPos->ForwardLink; | |
} else { | |
HighlightPos = gUserSelectableOptions.ForwardLink; | |
} | |
break; | |
case SCAN_LEFT: | |
if (HighlightOption->Sequence > HighlightOption->MinSequence) { | |
HighlightPos = HighlightPos->BackLink; | |
} else { | |
HighlightPos = gUserSelectableOptions.BackLink; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case CHAR_CARRIAGE_RETURN: | |
*UserSelection = HighlightOption->OptionType; | |
return; | |
default: | |
if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptYes | UPPER_LOWER_CASE_OFFSET)) && | |
((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel))) | |
{ | |
*UserSelection = EfiHiiPopupSelectionYes; | |
return; | |
} else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptNo| UPPER_LOWER_CASE_OFFSET)) && | |
((PopupType == EfiHiiPopupTypeYesNo) || (PopupType == EfiHiiPopupTypeYesNoCancel))) | |
{ | |
*UserSelection = EfiHiiPopupSelectionNo; | |
return; | |
} else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptOk | UPPER_LOWER_CASE_OFFSET)) && | |
((PopupType == EfiHiiPopupTypeOk) || (PopupType == EfiHiiPopupTypeOkCancel))) | |
{ | |
*UserSelection = EfiHiiPopupSelectionOk; | |
return; | |
} else if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptCancel| UPPER_LOWER_CASE_OFFSET)) && | |
((PopupType == EfiHiiPopupTypeOkCancel) || (PopupType == EfiHiiPopupTypeYesNoCancel))) | |
{ | |
*UserSelection = EfiHiiPopupSelectionCancel; | |
return; | |
} | |
break; | |
} | |
} while (TRUE); | |
} | |
/** | |
Get the offset in the input string when the width reaches to a fixed one. | |
The input string may contain NARROW_CHAR and WIDE_CHAR. | |
Notice: the input string doesn't contain line break characters. | |
@param String The input string to be counted. | |
@param MaxWidth The max length this function supported. | |
@param Offset The max index of the string can be show out. If string's width less than MaxWidth, offset will point to the "\0" of the string. | |
**/ | |
VOID | |
GetStringOffsetWithWidth ( | |
IN CHAR16 *String, | |
IN UINTN MaxWidth, | |
OUT UINTN *Offset | |
) | |
{ | |
UINTN StringWidth; | |
UINTN CharWidth; | |
UINTN StrOffset; | |
StringWidth = 0; | |
CharWidth = 1; | |
for (StrOffset = 0; String[StrOffset] != CHAR_NULL; StrOffset++) { | |
switch (String[StrOffset]) { | |
case NARROW_CHAR: | |
CharWidth = 1; | |
break; | |
case WIDE_CHAR: | |
CharWidth = 2; | |
break; | |
default: | |
StringWidth += CharWidth; | |
if (StringWidth >= MaxWidth) { | |
*Offset = StrOffset; | |
return; | |
} | |
} | |
} | |
*Offset = StrOffset; | |
} | |
/** | |
Parse the message to check if it contains line break characters. | |
For once call, caller can get the string for one line and the width of the string. | |
This function call be called recursively to parse the whole InputString. | |
(Notice: current implementation, it only checks \r, \n characters, it deals \r,\n,\n\r same as \r\n.) | |
@param InputString String description for this option. | |
@param OutputString Buffer to copy the string into, caller is responsible for freeing the buffer. | |
@param OutputStrWidth The width of OutputString. | |
@param Index Where in InputString to start the copy process | |
@return Returns the number of CHAR16 characters that were copied into the OutputString buffer, include the '\0' info. | |
**/ | |
UINTN | |
ParseMessageString ( | |
IN CHAR16 *InputString, | |
OUT CHAR16 **OutputString, | |
OUT UINTN *OutputStrWidth, | |
IN OUT UINTN *Index | |
) | |
{ | |
UINTN StrOffset; | |
if ((InputString == NULL) || (Index == NULL) || (OutputString == NULL)) { | |
return 0; | |
} | |
*OutputStrWidth = 0; | |
// | |
// Check the string to see if there are line break characters in the string | |
// | |
for (StrOffset = 0; | |
InputString[*Index + StrOffset] != CHAR_CARRIAGE_RETURN && InputString[*Index + StrOffset] != CHAR_LINEFEED && InputString[*Index + StrOffset] != CHAR_NULL; | |
StrOffset++ | |
) | |
{ | |
} | |
// | |
// The CHAR_NULL has process last time, this time just return 0 to stand for finishing parsing the InputString. | |
// | |
if ((StrOffset == 0) && (InputString[*Index + StrOffset] == CHAR_NULL)) { | |
return 0; | |
} | |
// | |
// Copy the string to OutputString buffer and calculate the width of OutputString. | |
// | |
*OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof (CHAR16)); | |
if (*OutputString == NULL) { | |
return 0; | |
} | |
CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof (CHAR16)); | |
*OutputStrWidth = (GetStringWidth (*OutputString) -2) / 2; | |
// | |
// Update the value of Index, can be used for marking where to check the input string for next call. | |
// | |
if (InputString[*Index + StrOffset] == CHAR_LINEFEED) { | |
// | |
// Skip the /n or /n/r info. | |
// | |
if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) { | |
*Index = (*Index + StrOffset + 2); | |
} else { | |
*Index = (*Index + StrOffset + 1); | |
} | |
} else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) { | |
// | |
// Skip the /r or /r/n info. | |
// | |
if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) { | |
*Index = (*Index + StrOffset + 2); | |
} else { | |
*Index = (*Index + StrOffset + 1); | |
} | |
} else { | |
*Index = (*Index + StrOffset); | |
} | |
return StrOffset + 1; | |
} | |
/** | |
Calculate the position of the popup. | |
@param PopupType Type of the popup to display. | |
@param ScreenForPopup The screen dimensions for the popup. | |
**/ | |
VOID | |
CalculatePopupPosition ( | |
IN EFI_HII_POPUP_TYPE PopupType, | |
OUT EFI_SCREEN_DESCRIPTOR *ScreenForPopup | |
) | |
{ | |
CHAR16 *OutputString; | |
UINTN StringIndex; | |
UINTN OutputStrWidth; | |
UINTN OptionRowWidth; | |
UINTN Columns; | |
UINTN Rows; | |
OptionRowWidth = 0; | |
// | |
// Calculate the row number which is needed to show the message string and the max width of the string in one row. | |
// | |
for (StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0;) { | |
gMesStrLineNum++; | |
if (gMaxRowWidth < OutputStrWidth) { | |
gMaxRowWidth = OutputStrWidth; | |
} | |
FreePool (OutputString); | |
} | |
// | |
// Calculate the row width for the selectable options.(OptionRowWidth = Number * SkipWidth + OptionWidth) | |
// | |
if (PopupType == EfiHiiPopupTypeOk) { | |
OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *2 + USER_SELECTABLE_OPTION_OK_WIDTH; | |
} else if (PopupType == EfiHiiPopupTypeOkCancel) { | |
OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_OK_CAL_WIDTH; | |
} else if (PopupType == EfiHiiPopupTypeYesNo) { | |
OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_YES_NO_WIDTH; | |
} else if (PopupType == EfiHiiPopupTypeYesNoCancel) { | |
OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *4 + USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH; | |
} | |
if (OptionRowWidth > gMaxRowWidth) { | |
gMaxRowWidth = OptionRowWidth; | |
} | |
// | |
// Avialble row width for message string = screen width - left popup border width - right popup border width. | |
// Avialble line number for message string = screen height - 1 - popup header height - popup footer height. | |
// (Notice: screen height - 1 because in current UI page, the bottom row of srceen is usded to show Status Bar,not for form itself. | |
// So we don't use the bottom row for popup either. If macro STATUS_BAR_HEIGHT changed, we also need to update the height here.) | |
// | |
// Select the smaller one between actual dimension of message string and the avialble dimension for message string. | |
// | |
gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows); | |
gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER); | |
gMesStrLineNum = MIN (gMesStrLineNum, Rows -1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT); | |
// | |
// Calculate the start column, end column, top row and bottom row for the popup. | |
// | |
ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2; | |
ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1; | |
ScreenForPopup->TopRow = (Rows - 1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT - gMesStrLineNum) / 2; | |
ScreenForPopup->BottomRow = ScreenForPopup->TopRow + gMesStrLineNum + POPUP_FOOTER_HEIGHT + POPUP_HEADER_HEIGHT - 1; | |
} | |
/** | |
Draw the Message box. | |
+-------------------------------------------+ | |
| ERROR/WARNING/INFO | | |
|-------------------------------------------| | |
| popup messages | | |
| | | |
| user selectable options | | |
+-------------------------------------------+ | |
@param PopupStyle Popup style to use. | |
**/ | |
EFI_STATUS | |
DrawMessageBox ( | |
IN EFI_HII_POPUP_STYLE PopupStyle | |
) | |
{ | |
UINTN Index; | |
UINTN Length; | |
UINTN EndCol; | |
UINTN TopRow; | |
UINTN StartCol; | |
UINTN BottomRow; | |
CHAR16 Character; | |
UINTN DisplayRow; | |
UINTN StringIndex; | |
CHAR16 *TempString; | |
CHAR16 *OutputString; | |
UINTN ColDimension; | |
UINTN OutputStrWidth; | |
UINTN DrawMesStrRowNum; | |
EndCol = gPopupDimensions.RightColumn; | |
TopRow = gPopupDimensions.TopRow; | |
StartCol = gPopupDimensions.LeftColumn; | |
BottomRow = gPopupDimensions.BottomRow; | |
ColDimension = EndCol - StartCol + 1; | |
DrawMesStrRowNum = 0; | |
// | |
// 1. Draw the top of the message box. | |
// | |
Character = BOXDRAW_DOWN_RIGHT; | |
PrintCharAt (StartCol, TopRow, Character); | |
Character = BOXDRAW_HORIZONTAL; | |
for (Index = StartCol; Index + 1 < EndCol; Index++) { | |
PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
} | |
Character = BOXDRAW_DOWN_LEFT; | |
PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
// | |
// 2. Draw the prompt string for different popup styles. | |
// | |
Character = BOXDRAW_VERTICAL; | |
DisplayRow = TopRow + POPUP_BORDER; | |
ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); | |
PrintCharAt (StartCol, DisplayRow, Character); | |
PrintCharAt (EndCol, DisplayRow, Character); | |
if (PopupStyle == EfiHiiPopupStyleError) { | |
PrintStringAt ((ColDimension - (GetStringWidth (gErrorPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gErrorPopup); | |
} else if (PopupStyle == EfiHiiPopupStyleWarning) { | |
PrintStringAt ((ColDimension - (GetStringWidth (gWarningPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gWarningPopup); | |
} else { | |
PrintStringAt ((ColDimension - (GetStringWidth (gInfoPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gInfoPopup); | |
} | |
// | |
// 3. Draw the horizontal line below the prompt string for different popup styles. | |
// | |
DisplayRow = TopRow + POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT; | |
ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); | |
Character = BOXDRAW_HORIZONTAL; | |
for (Index = StartCol + 1; Index < EndCol; Index++) { | |
PrintCharAt (Index, DisplayRow, Character); | |
} | |
Character = BOXDRAW_VERTICAL; | |
PrintCharAt (StartCol, DisplayRow, Character); | |
PrintCharAt (EndCol, DisplayRow, Character); | |
// | |
// 4. Draw the mesage string. | |
// | |
DisplayRow = TopRow + POPUP_HEADER_HEIGHT; | |
for (Index = DisplayRow, StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) { | |
ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ()); | |
PrintCharAt (StartCol, Index, Character); | |
PrintCharAt (EndCol, Index, Character); | |
if (OutputStrWidth > gMaxRowWidth) { | |
// | |
// OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead. | |
// | |
GetStringOffsetWithWidth (OutputString, gMaxRowWidth, &Length); | |
TempString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); | |
if (TempString == NULL) { | |
FreePool (OutputString); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
StrnCpyS (TempString, Length + 1, OutputString, Length - 3); | |
StrCatS (TempString, Length + 1, L"..."); | |
PrintStringAt ((ColDimension - gMaxRowWidth) / 2 + StartCol, Index, TempString); | |
FreePool (TempString); | |
} else { | |
PrintStringAt ((ColDimension - OutputStrWidth) / 2 + StartCol, Index, OutputString); | |
} | |
Index++; | |
DrawMesStrRowNum++; | |
FreePool (OutputString); | |
} | |
// | |
// 5. Draw an empty line after message string. | |
// | |
ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ()); | |
PrintCharAt (StartCol, Index, Character); | |
PrintCharAt (EndCol, Index, Character); | |
// | |
// Check whether the actual string row number beyond the MesStrRowNum, if yes, print the ...... in the row. | |
// | |
if ((OutputStrWidth > 0) && (DrawMesStrRowNum >= gMesStrLineNum)) { | |
PrintStringAt ((ColDimension - StrLen (L"......")) / 2 + StartCol, Index, L"......"); | |
} | |
// | |
// 6. Draw an empty line which is used to show user selectable options, will draw concrete option strings in function GetUserSelection(). | |
// | |
Character = BOXDRAW_VERTICAL; | |
DisplayRow = BottomRow - POPUP_BORDER; | |
ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ()); | |
PrintCharAt (StartCol, DisplayRow, Character); | |
PrintCharAt (EndCol, DisplayRow, Character); | |
// | |
// 7. Draw the bottom of the message box. | |
// | |
Character = BOXDRAW_UP_RIGHT; | |
PrintCharAt (StartCol, BottomRow, Character); | |
Character = BOXDRAW_HORIZONTAL; | |
for (Index = StartCol; Index + 1 < EndCol; Index++) { | |
PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
} | |
Character = BOXDRAW_UP_LEFT; | |
PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
return EFI_SUCCESS; | |
} | |
/** | |
Displays a popup window. | |
@param This A pointer to the EFI_HII_POPUP_PROTOCOL instance. | |
@param PopupStyle Popup style to use. | |
@param PopupType Type of the popup to display. | |
@param HiiHandle HII handle of the string pack containing Message | |
@param Message A message to display in the popup box. | |
@param UserSelection User selection. | |
@retval EFI_SUCCESS The popup box was successfully displayed. | |
@retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string. | |
@retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CreatePopup ( | |
IN EFI_HII_POPUP_PROTOCOL *This, | |
IN EFI_HII_POPUP_STYLE PopupStyle, | |
IN EFI_HII_POPUP_TYPE PopupType, | |
IN EFI_HII_HANDLE HiiHandle, | |
IN EFI_STRING_ID Message, | |
OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL | |
) | |
{ | |
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; | |
EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode; | |
EFI_STATUS Status; | |
if ((PopupType < EfiHiiPopupTypeOk) || (PopupType > EfiHiiPopupTypeYesNoCancel)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((HiiHandle == NULL) || (Message == 0)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
gMessageString = HiiGetString (HiiHandle, Message, NULL); | |
if (gMessageString == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
ConOut = gST->ConOut; | |
gMaxRowWidth = 0; | |
gMesStrLineNum = 0; | |
CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode)); | |
ConOut->EnableCursor (ConOut, FALSE); | |
ConOut->SetAttribute (ConOut, GetPopupColor ()); | |
CalculatePopupPosition (PopupType, &gPopupDimensions); | |
Status = DrawMessageBox (PopupStyle); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
// | |
// Add user selectable options to option list: gUserSelectableOptions | |
// | |
Status = AddUserSelectableOptions (PopupType); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
GetUserSelection (PopupType, UserSelection); | |
Done: | |
// | |
// Restore Conout attributes and free the resources allocate before. | |
// | |
ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible); | |
ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); | |
ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute); | |
FreeSelectableOptions (&gUserSelectableOptions); | |
FreePool (gMessageString); | |
return Status; | |
} |