| /** @file | |
| Implementation for Hii Popup Protocol. | |
| Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #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; | |
| } | |