This commit removes unnecessary parentheses in 'if' statements to resolve the build failures by the XCODE5 tool chain. Cc: Eric Dong <eric.dong@intel.com> Cc: Dandan Bi <dandan.bi@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			731 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			731 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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;
 | 
						|
}
 | 
						|
 |