REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1693 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1693 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
Implementation for handling user input from the User Interfaces.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "FormDisplay.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Get maximum and minimum info from this opcode.
 | 
						|
 | 
						|
  @param  OpCode            Pointer to the current input opcode.
 | 
						|
  @param  Minimum           The minimum size info for this opcode.
 | 
						|
  @param  Maximum           The maximum size info for this opcode.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GetFieldFromOp (
 | 
						|
  IN   EFI_IFR_OP_HEADER  *OpCode,
 | 
						|
  OUT  UINTN              *Minimum,
 | 
						|
  OUT  UINTN              *Maximum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IFR_STRING    *StringOp;
 | 
						|
  EFI_IFR_PASSWORD  *PasswordOp;
 | 
						|
 | 
						|
  if (OpCode->OpCode == EFI_IFR_STRING_OP) {
 | 
						|
    StringOp = (EFI_IFR_STRING *)OpCode;
 | 
						|
    *Minimum = StringOp->MinSize;
 | 
						|
    *Maximum = StringOp->MaxSize;
 | 
						|
  } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
 | 
						|
    PasswordOp = (EFI_IFR_PASSWORD *)OpCode;
 | 
						|
    *Minimum   = PasswordOp->MinSize;
 | 
						|
    *Maximum   = PasswordOp->MaxSize;
 | 
						|
  } else {
 | 
						|
    *Minimum = 0;
 | 
						|
    *Maximum = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get string or password input from user.
 | 
						|
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
  @param  Prompt            The prompt string shown on popup window.
 | 
						|
  @param  StringPtr         Old user input and destination for use input string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If string input is read successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadString (
 | 
						|
  IN     UI_MENU_OPTION  *MenuOption,
 | 
						|
  IN     CHAR16          *Prompt,
 | 
						|
  IN OUT CHAR16          *StringPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  EFI_INPUT_KEY                  Key;
 | 
						|
  CHAR16                         NullCharacter;
 | 
						|
  UINTN                          ScreenSize;
 | 
						|
  CHAR16                         Space[2];
 | 
						|
  CHAR16                         KeyPad[2];
 | 
						|
  CHAR16                         *TempString;
 | 
						|
  CHAR16                         *BufferedString;
 | 
						|
  UINTN                          Index;
 | 
						|
  UINTN                          Index2;
 | 
						|
  UINTN                          Count;
 | 
						|
  UINTN                          Start;
 | 
						|
  UINTN                          Top;
 | 
						|
  UINTN                          DimensionsWidth;
 | 
						|
  UINTN                          DimensionsHeight;
 | 
						|
  UINTN                          CurrentCursor;
 | 
						|
  BOOLEAN                        CursorVisible;
 | 
						|
  UINTN                          Minimum;
 | 
						|
  UINTN                          Maximum;
 | 
						|
  FORM_DISPLAY_ENGINE_STATEMENT  *Question;
 | 
						|
  BOOLEAN                        IsPassword;
 | 
						|
  UINTN                          MaxLen;
 | 
						|
 | 
						|
  DimensionsWidth  = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
 | 
						|
  DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
 | 
						|
 | 
						|
  NullCharacter = CHAR_NULL;
 | 
						|
  ScreenSize    = GetStringWidth (Prompt) / sizeof (CHAR16);
 | 
						|
  Space[0]      = L' ';
 | 
						|
  Space[1]      = CHAR_NULL;
 | 
						|
 | 
						|
  Question = MenuOption->ThisTag;
 | 
						|
  GetFieldFromOp (Question->OpCode, &Minimum, &Maximum);
 | 
						|
 | 
						|
  if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
 | 
						|
    IsPassword = TRUE;
 | 
						|
  } else {
 | 
						|
    IsPassword = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  MaxLen     = Maximum + 1;
 | 
						|
  TempString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
 | 
						|
  ASSERT (TempString);
 | 
						|
 | 
						|
  if (ScreenSize < (Maximum + 1)) {
 | 
						|
    ScreenSize = Maximum + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((ScreenSize + 2) > DimensionsWidth) {
 | 
						|
    ScreenSize = DimensionsWidth - 2;
 | 
						|
  }
 | 
						|
 | 
						|
  BufferedString = AllocateZeroPool (ScreenSize * 2);
 | 
						|
  ASSERT (BufferedString);
 | 
						|
 | 
						|
  Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;
 | 
						|
  Top   = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Display prompt for string
 | 
						|
  //
 | 
						|
  // CreateDialog (NULL, "", Prompt, Space, "", NULL);
 | 
						|
  CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
 | 
						|
  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
 | 
						|
 | 
						|
  CursorVisible = gST->ConOut->Mode->CursorVisible;
 | 
						|
  gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | 
						|
 | 
						|
  CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
 | 
						|
  if (CurrentCursor != 0) {
 | 
						|
    //
 | 
						|
    // Show the string which has beed saved before.
 | 
						|
    //
 | 
						|
    SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
 | 
						|
    PrintStringAt (Start + 1, Top + 3, BufferedString);
 | 
						|
 | 
						|
    if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
 | 
						|
      Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
 | 
						|
    } else {
 | 
						|
      Index = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsPassword) {
 | 
						|
      gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
 | 
						|
    }
 | 
						|
 | 
						|
    for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
 | 
						|
      BufferedString[Count] = StringPtr[Index];
 | 
						|
 | 
						|
      if (IsPassword) {
 | 
						|
        PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!IsPassword) {
 | 
						|
      PrintStringAt (Start + 1, Top + 3, BufferedString);
 | 
						|
    }
 | 
						|
 | 
						|
    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
    gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    Status = WaitForKeyStroke (&Key);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
 | 
						|
    switch (Key.UnicodeChar) {
 | 
						|
      case CHAR_NULL:
 | 
						|
        switch (Key.ScanCode) {
 | 
						|
          case SCAN_LEFT:
 | 
						|
            if (CurrentCursor > 0) {
 | 
						|
              CurrentCursor--;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
 | 
						|
          case SCAN_RIGHT:
 | 
						|
            if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
 | 
						|
              CurrentCursor++;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
 | 
						|
          case SCAN_ESC:
 | 
						|
            FreePool (TempString);
 | 
						|
            FreePool (BufferedString);
 | 
						|
            gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
            gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
          case SCAN_DELETE:
 | 
						|
            for (Index = CurrentCursor; StringPtr[Index] != CHAR_NULL; Index++) {
 | 
						|
              StringPtr[Index] = StringPtr[Index + 1];
 | 
						|
              PrintCharAt (Start + Index + 1, Top + 3, IsPassword && StringPtr[Index] != CHAR_NULL ? L'*' : StringPtr[Index]);
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
 | 
						|
          default:
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case CHAR_CARRIAGE_RETURN:
 | 
						|
        if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
 | 
						|
          FreePool (TempString);
 | 
						|
          FreePool (BufferedString);
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
          gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
 | 
						|
          return EFI_SUCCESS;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Simply create a popup to tell the user that they had typed in too few characters.
 | 
						|
          // To save code space, we can then treat this as an error and return back to the menu.
 | 
						|
          //
 | 
						|
          do {
 | 
						|
            CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);
 | 
						|
          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | 
						|
 | 
						|
          FreePool (TempString);
 | 
						|
          FreePool (BufferedString);
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
          gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
 | 
						|
          return EFI_DEVICE_ERROR;
 | 
						|
        }
 | 
						|
 | 
						|
      case CHAR_BACKSPACE:
 | 
						|
        if ((StringPtr[0] != CHAR_NULL) && (CurrentCursor != 0)) {
 | 
						|
          for (Index = 0; Index < CurrentCursor - 1; Index++) {
 | 
						|
            TempString[Index] = StringPtr[Index];
 | 
						|
          }
 | 
						|
 | 
						|
          Count = GetStringWidth (StringPtr) / 2 - 1;
 | 
						|
          if (Count >= CurrentCursor) {
 | 
						|
            for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {
 | 
						|
              TempString[Index] = StringPtr[Index2];
 | 
						|
            }
 | 
						|
 | 
						|
            TempString[Index] = CHAR_NULL;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Effectively truncate string by 1 character
 | 
						|
          //
 | 
						|
          StrCpyS (StringPtr, MaxLen, TempString);
 | 
						|
          CurrentCursor--;
 | 
						|
        }
 | 
						|
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        // If it is the beginning of the string, don't worry about checking maximum limits
 | 
						|
        //
 | 
						|
        if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
 | 
						|
          StrnCpyS (StringPtr, MaxLen, &Key.UnicodeChar, 1);
 | 
						|
          CurrentCursor++;
 | 
						|
        } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
 | 
						|
          KeyPad[0] = Key.UnicodeChar;
 | 
						|
          KeyPad[1] = CHAR_NULL;
 | 
						|
          Count     = GetStringWidth (StringPtr) / 2 - 1;
 | 
						|
          if (CurrentCursor < Count) {
 | 
						|
            for (Index = 0; Index < CurrentCursor; Index++) {
 | 
						|
              TempString[Index] = StringPtr[Index];
 | 
						|
            }
 | 
						|
 | 
						|
            TempString[Index] = CHAR_NULL;
 | 
						|
            StrCatS (TempString, MaxLen, KeyPad);
 | 
						|
            StrCatS (TempString, MaxLen, StringPtr + CurrentCursor);
 | 
						|
            StrCpyS (StringPtr, MaxLen, TempString);
 | 
						|
          } else {
 | 
						|
            StrCatS (StringPtr, MaxLen, KeyPad);
 | 
						|
          }
 | 
						|
 | 
						|
          CurrentCursor++;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // If the width of the input string is now larger than the screen, we nee to
 | 
						|
        // adjust the index to start printing portions of the string
 | 
						|
        //
 | 
						|
        SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
 | 
						|
        PrintStringAt (Start + 1, Top + 3, BufferedString);
 | 
						|
 | 
						|
        if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
 | 
						|
          Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
 | 
						|
        } else {
 | 
						|
          Index = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if (IsPassword) {
 | 
						|
          gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
 | 
						|
        }
 | 
						|
 | 
						|
        for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
 | 
						|
          BufferedString[Count] = StringPtr[Index];
 | 
						|
 | 
						|
          if (IsPassword) {
 | 
						|
            PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (!IsPassword) {
 | 
						|
          PrintStringAt (Start + 1, Top + 3, BufferedString);
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
    gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
 | 
						|
  } while (TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Adjust the value to the correct one. Rules follow the sample:
 | 
						|
  like:  Year change:  2012.02.29 -> 2013.02.29 -> 2013.02.01
 | 
						|
         Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
 | 
						|
 | 
						|
  @param  QuestionValue     Pointer to current question.
 | 
						|
  @param  Sequence          The sequence of the field in the question.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
AdjustQuestionValue (
 | 
						|
  IN  EFI_HII_VALUE  *QuestionValue,
 | 
						|
  IN  UINT8          Sequence
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   Month;
 | 
						|
  UINT16  Year;
 | 
						|
  UINT8   Maximum;
 | 
						|
  UINT8   Minimum;
 | 
						|
 | 
						|
  Month   = QuestionValue->Value.date.Month;
 | 
						|
  Year    = QuestionValue->Value.date.Year;
 | 
						|
  Minimum = 1;
 | 
						|
 | 
						|
  switch (Month) {
 | 
						|
    case 2:
 | 
						|
      if (((Year % 4) == 0) && (((Year % 100) != 0) || ((Year % 400) == 0))) {
 | 
						|
        Maximum = 29;
 | 
						|
      } else {
 | 
						|
        Maximum = 28;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    case 4:
 | 
						|
    case 6:
 | 
						|
    case 9:
 | 
						|
    case 11:
 | 
						|
      Maximum = 30;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      Maximum = 31;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Change the month area.
 | 
						|
  //
 | 
						|
  if (Sequence == 0) {
 | 
						|
    if (QuestionValue->Value.date.Day > Maximum) {
 | 
						|
      QuestionValue->Value.date.Day = Maximum;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Change the Year area.
 | 
						|
  //
 | 
						|
  if (Sequence == 2) {
 | 
						|
    if (QuestionValue->Value.date.Day > Maximum) {
 | 
						|
      QuestionValue->Value.date.Day = Minimum;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get field info from numeric opcode.
 | 
						|
 | 
						|
  @param  OpCode            Pointer to the current input opcode.
 | 
						|
  @param  IntInput          Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
 | 
						|
  @param  QuestionValue     Input question value, with EFI_HII_VALUE type.
 | 
						|
  @param  Value             Return question value, always return UINT64 type.
 | 
						|
  @param  Minimum           The minimum size info for this opcode.
 | 
						|
  @param  Maximum           The maximum size info for this opcode.
 | 
						|
  @param  Step              The step size info for this opcode.
 | 
						|
  @param  StorageWidth      The storage width info for this opcode.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GetValueFromNum (
 | 
						|
  IN  EFI_IFR_OP_HEADER  *OpCode,
 | 
						|
  IN  BOOLEAN            IntInput,
 | 
						|
  IN  EFI_HII_VALUE      *QuestionValue,
 | 
						|
  OUT UINT64             *Value,
 | 
						|
  OUT UINT64             *Minimum,
 | 
						|
  OUT UINT64             *Maximum,
 | 
						|
  OUT UINT64             *Step,
 | 
						|
  OUT UINT16             *StorageWidth
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IFR_NUMERIC  *NumericOp;
 | 
						|
 | 
						|
  NumericOp = (EFI_IFR_NUMERIC *)OpCode;
 | 
						|
 | 
						|
  switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
 | 
						|
    case EFI_IFR_NUMERIC_SIZE_1:
 | 
						|
      if (IntInput) {
 | 
						|
        *Minimum = (INT64)(INT8)NumericOp->data.u8.MinValue;
 | 
						|
        *Maximum = (INT64)(INT8)NumericOp->data.u8.MaxValue;
 | 
						|
        *Value   = (INT64)(INT8)QuestionValue->Value.u8;
 | 
						|
      } else {
 | 
						|
        *Minimum = NumericOp->data.u8.MinValue;
 | 
						|
        *Maximum = NumericOp->data.u8.MaxValue;
 | 
						|
        *Value   = QuestionValue->Value.u8;
 | 
						|
      }
 | 
						|
 | 
						|
      *Step         = NumericOp->data.u8.Step;
 | 
						|
      *StorageWidth = (UINT16)sizeof (UINT8);
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_NUMERIC_SIZE_2:
 | 
						|
      if (IntInput) {
 | 
						|
        *Minimum = (INT64)(INT16)NumericOp->data.u16.MinValue;
 | 
						|
        *Maximum = (INT64)(INT16)NumericOp->data.u16.MaxValue;
 | 
						|
        *Value   = (INT64)(INT16)QuestionValue->Value.u16;
 | 
						|
      } else {
 | 
						|
        *Minimum = NumericOp->data.u16.MinValue;
 | 
						|
        *Maximum = NumericOp->data.u16.MaxValue;
 | 
						|
        *Value   = QuestionValue->Value.u16;
 | 
						|
      }
 | 
						|
 | 
						|
      *Step         = NumericOp->data.u16.Step;
 | 
						|
      *StorageWidth = (UINT16)sizeof (UINT16);
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_NUMERIC_SIZE_4:
 | 
						|
      if (IntInput) {
 | 
						|
        *Minimum = (INT64)(INT32)NumericOp->data.u32.MinValue;
 | 
						|
        *Maximum = (INT64)(INT32)NumericOp->data.u32.MaxValue;
 | 
						|
        *Value   = (INT64)(INT32)QuestionValue->Value.u32;
 | 
						|
      } else {
 | 
						|
        *Minimum = NumericOp->data.u32.MinValue;
 | 
						|
        *Maximum = NumericOp->data.u32.MaxValue;
 | 
						|
        *Value   = QuestionValue->Value.u32;
 | 
						|
      }
 | 
						|
 | 
						|
      *Step         = NumericOp->data.u32.Step;
 | 
						|
      *StorageWidth = (UINT16)sizeof (UINT32);
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_NUMERIC_SIZE_8:
 | 
						|
      if (IntInput) {
 | 
						|
        *Minimum = (INT64)NumericOp->data.u64.MinValue;
 | 
						|
        *Maximum = (INT64)NumericOp->data.u64.MaxValue;
 | 
						|
        *Value   = (INT64)QuestionValue->Value.u64;
 | 
						|
      } else {
 | 
						|
        *Minimum = NumericOp->data.u64.MinValue;
 | 
						|
        *Maximum = NumericOp->data.u64.MaxValue;
 | 
						|
        *Value   = QuestionValue->Value.u64;
 | 
						|
      }
 | 
						|
 | 
						|
      *Step         = NumericOp->data.u64.Step;
 | 
						|
      *StorageWidth = (UINT16)sizeof (UINT64);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (*Maximum == 0) {
 | 
						|
    *Maximum = (UINT64)-1;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine reads a numeric value from the user input.
 | 
						|
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If numerical input is read successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetNumericInput (
 | 
						|
  IN  UI_MENU_OPTION  *MenuOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                          Column;
 | 
						|
  UINTN                          Row;
 | 
						|
  CHAR16                         InputText[MAX_NUMERIC_INPUT_WIDTH];
 | 
						|
  CHAR16                         FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
 | 
						|
  UINT64                         PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
 | 
						|
  UINTN                          Count;
 | 
						|
  UINTN                          Loop;
 | 
						|
  BOOLEAN                        ManualInput;
 | 
						|
  BOOLEAN                        HexInput;
 | 
						|
  BOOLEAN                        IntInput;
 | 
						|
  BOOLEAN                        Negative;
 | 
						|
  BOOLEAN                        ValidateFail;
 | 
						|
  BOOLEAN                        DateOrTime;
 | 
						|
  UINTN                          InputWidth;
 | 
						|
  UINT64                         EditValue;
 | 
						|
  UINT64                         Step;
 | 
						|
  UINT64                         Minimum;
 | 
						|
  UINT64                         Maximum;
 | 
						|
  UINTN                          EraseLen;
 | 
						|
  UINT8                          Digital;
 | 
						|
  EFI_INPUT_KEY                  Key;
 | 
						|
  EFI_HII_VALUE                  *QuestionValue;
 | 
						|
  FORM_DISPLAY_ENGINE_STATEMENT  *Question;
 | 
						|
  EFI_IFR_NUMERIC                *NumericOp;
 | 
						|
  UINT16                         StorageWidth;
 | 
						|
 | 
						|
  Column            = MenuOption->OptCol;
 | 
						|
  Row               = MenuOption->Row;
 | 
						|
  PreviousNumber[0] = 0;
 | 
						|
  Count             = 0;
 | 
						|
  InputWidth        = 0;
 | 
						|
  Digital           = 0;
 | 
						|
  StorageWidth      = 0;
 | 
						|
  Minimum           = 0;
 | 
						|
  Maximum           = 0;
 | 
						|
  NumericOp         = NULL;
 | 
						|
  IntInput          = FALSE;
 | 
						|
  HexInput          = FALSE;
 | 
						|
  Negative          = FALSE;
 | 
						|
  ValidateFail      = FALSE;
 | 
						|
 | 
						|
  Question      = MenuOption->ThisTag;
 | 
						|
  QuestionValue = &Question->CurrentValue;
 | 
						|
  ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16));
 | 
						|
 | 
						|
  //
 | 
						|
  // Only two case, user can enter to this function: Enter and +/- case.
 | 
						|
  // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
 | 
						|
  //
 | 
						|
  ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
 | 
						|
 | 
						|
  if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
 | 
						|
    DateOrTime = TRUE;
 | 
						|
  } else {
 | 
						|
    DateOrTime = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Prepare Value to be edit
 | 
						|
  //
 | 
						|
  EraseLen  = 0;
 | 
						|
  EditValue = 0;
 | 
						|
  if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
 | 
						|
    Step    = 1;
 | 
						|
    Minimum = 1;
 | 
						|
 | 
						|
    switch (MenuOption->Sequence) {
 | 
						|
      case 0:
 | 
						|
        Maximum   = 12;
 | 
						|
        EraseLen  = 4;
 | 
						|
        EditValue = QuestionValue->Value.date.Month;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 1:
 | 
						|
        switch (QuestionValue->Value.date.Month) {
 | 
						|
          case 2:
 | 
						|
            if (((QuestionValue->Value.date.Year % 4) == 0) &&
 | 
						|
                (((QuestionValue->Value.date.Year % 100) != 0) ||
 | 
						|
                 ((QuestionValue->Value.date.Year % 400) == 0)))
 | 
						|
            {
 | 
						|
              Maximum = 29;
 | 
						|
            } else {
 | 
						|
              Maximum = 28;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          case 4:
 | 
						|
          case 6:
 | 
						|
          case 9:
 | 
						|
          case 11:
 | 
						|
            Maximum = 30;
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            Maximum = 31;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        EraseLen  = 3;
 | 
						|
        EditValue = QuestionValue->Value.date.Day;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 2:
 | 
						|
        Maximum   = 0xffff;
 | 
						|
        EraseLen  = 5;
 | 
						|
        EditValue = QuestionValue->Value.date.Year;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
 | 
						|
    Step    = 1;
 | 
						|
    Minimum = 0;
 | 
						|
 | 
						|
    switch (MenuOption->Sequence) {
 | 
						|
      case 0:
 | 
						|
        Maximum   = 23;
 | 
						|
        EraseLen  = 4;
 | 
						|
        EditValue = QuestionValue->Value.time.Hour;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 1:
 | 
						|
        Maximum   = 59;
 | 
						|
        EraseLen  = 3;
 | 
						|
        EditValue = QuestionValue->Value.time.Minute;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 2:
 | 
						|
        Maximum   = 59;
 | 
						|
        EraseLen  = 3;
 | 
						|
        EditValue = QuestionValue->Value.time.Second;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);
 | 
						|
    NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode;
 | 
						|
    GetValueFromNum (Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);
 | 
						|
    EraseLen = gOptionBlockWidth;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {
 | 
						|
    if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX) {
 | 
						|
      HexInput = TRUE;
 | 
						|
    } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0) {
 | 
						|
      //
 | 
						|
      // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
 | 
						|
      //
 | 
						|
      IntInput = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Enter from "Enter" input, clear the old word showing.
 | 
						|
  //
 | 
						|
  if (ManualInput) {
 | 
						|
    if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
 | 
						|
      if (HexInput) {
 | 
						|
        InputWidth = StorageWidth * 2;
 | 
						|
      } else {
 | 
						|
        switch (StorageWidth) {
 | 
						|
          case 1:
 | 
						|
            InputWidth = 3;
 | 
						|
            break;
 | 
						|
 | 
						|
          case 2:
 | 
						|
            InputWidth = 5;
 | 
						|
            break;
 | 
						|
 | 
						|
          case 4:
 | 
						|
            InputWidth = 10;
 | 
						|
            break;
 | 
						|
 | 
						|
          case 8:
 | 
						|
            InputWidth = 20;
 | 
						|
            break;
 | 
						|
 | 
						|
          default:
 | 
						|
            InputWidth = 0;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (IntInput) {
 | 
						|
          //
 | 
						|
          // Support an extra '-' for negative number.
 | 
						|
          //
 | 
						|
          InputWidth += 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      InputText[0] = LEFT_NUMERIC_DELIMITER;
 | 
						|
      SetUnicodeMem (InputText + 1, InputWidth, L' ');
 | 
						|
      ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
 | 
						|
      InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
 | 
						|
      InputText[InputWidth + 2] = L'\0';
 | 
						|
 | 
						|
      PrintStringAt (Column, Row, InputText);
 | 
						|
      Column++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
 | 
						|
      if (MenuOption->Sequence == 2) {
 | 
						|
        InputWidth = 4;
 | 
						|
      } else {
 | 
						|
        InputWidth = 2;
 | 
						|
      }
 | 
						|
 | 
						|
      if (MenuOption->Sequence == 0) {
 | 
						|
        InputText[0] = LEFT_NUMERIC_DELIMITER;
 | 
						|
        SetUnicodeMem (InputText + 1, InputWidth, L' ');
 | 
						|
        InputText[InputWidth + 1] = DATE_SEPARATOR;
 | 
						|
        InputText[InputWidth + 2] = L'\0';
 | 
						|
      } else if (MenuOption->Sequence == 1) {
 | 
						|
        SetUnicodeMem (InputText, InputWidth, L' ');
 | 
						|
        InputText[InputWidth]     = DATE_SEPARATOR;
 | 
						|
        InputText[InputWidth + 1] = L'\0';
 | 
						|
      } else {
 | 
						|
        SetUnicodeMem (InputText, InputWidth, L' ');
 | 
						|
        InputText[InputWidth]     = RIGHT_NUMERIC_DELIMITER;
 | 
						|
        InputText[InputWidth + 1] = L'\0';
 | 
						|
      }
 | 
						|
 | 
						|
      PrintStringAt (Column, Row, InputText);
 | 
						|
      if (MenuOption->Sequence == 0) {
 | 
						|
        Column++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
 | 
						|
      InputWidth = 2;
 | 
						|
 | 
						|
      if (MenuOption->Sequence == 0) {
 | 
						|
        InputText[0] = LEFT_NUMERIC_DELIMITER;
 | 
						|
        SetUnicodeMem (InputText + 1, InputWidth, L' ');
 | 
						|
        InputText[InputWidth + 1] = TIME_SEPARATOR;
 | 
						|
        InputText[InputWidth + 2] = L'\0';
 | 
						|
      } else if (MenuOption->Sequence == 1) {
 | 
						|
        SetUnicodeMem (InputText, InputWidth, L' ');
 | 
						|
        InputText[InputWidth]     = TIME_SEPARATOR;
 | 
						|
        InputText[InputWidth + 1] = L'\0';
 | 
						|
      } else {
 | 
						|
        SetUnicodeMem (InputText, InputWidth, L' ');
 | 
						|
        InputText[InputWidth]     = RIGHT_NUMERIC_DELIMITER;
 | 
						|
        InputText[InputWidth + 1] = L'\0';
 | 
						|
      }
 | 
						|
 | 
						|
      PrintStringAt (Column, Row, InputText);
 | 
						|
      if (MenuOption->Sequence == 0) {
 | 
						|
        Column++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // First time we enter this handler, we need to check to see if
 | 
						|
  // we were passed an increment or decrement directive
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    Key.UnicodeChar = CHAR_NULL;
 | 
						|
    if (gDirection != 0) {
 | 
						|
      Key.ScanCode = gDirection;
 | 
						|
      gDirection   = 0;
 | 
						|
      goto TheKey2;
 | 
						|
    }
 | 
						|
 | 
						|
    WaitForKeyStroke (&Key);
 | 
						|
 | 
						|
TheKey2:
 | 
						|
    switch (Key.UnicodeChar) {
 | 
						|
      case '+':
 | 
						|
      case '-':
 | 
						|
        if (ManualInput && IntInput) {
 | 
						|
          //
 | 
						|
          // In Manual input mode, check whether input the negative flag.
 | 
						|
          //
 | 
						|
          if (Key.UnicodeChar == '-') {
 | 
						|
            if (Negative) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
 | 
						|
            Negative = TRUE;
 | 
						|
            PrintCharAt (Column++, Row, Key.UnicodeChar);
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (Key.UnicodeChar == '+') {
 | 
						|
            Key.ScanCode = SCAN_RIGHT;
 | 
						|
          } else {
 | 
						|
            Key.ScanCode = SCAN_LEFT;
 | 
						|
          }
 | 
						|
 | 
						|
          Key.UnicodeChar = CHAR_NULL;
 | 
						|
          goto TheKey2;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case CHAR_NULL:
 | 
						|
        switch (Key.ScanCode) {
 | 
						|
          case SCAN_LEFT:
 | 
						|
          case SCAN_RIGHT:
 | 
						|
            if (DateOrTime && !ManualInput) {
 | 
						|
              //
 | 
						|
              // By setting this value, we will return back to the caller.
 | 
						|
              // We need to do this since an auto-refresh will destroy the adjustment
 | 
						|
              // based on what the real-time-clock is showing.  So we always commit
 | 
						|
              // upon changing the value.
 | 
						|
              //
 | 
						|
              gDirection = SCAN_DOWN;
 | 
						|
            }
 | 
						|
 | 
						|
            if ((Step != 0) && !ManualInput) {
 | 
						|
              if (Key.ScanCode == SCAN_LEFT) {
 | 
						|
                if (IntInput) {
 | 
						|
                  if ((INT64)EditValue >= (INT64)Minimum + (INT64)Step) {
 | 
						|
                    EditValue = EditValue - Step;
 | 
						|
                  } else if ((INT64)EditValue > (INT64)Minimum) {
 | 
						|
                    EditValue = Minimum;
 | 
						|
                  } else {
 | 
						|
                    EditValue = Maximum;
 | 
						|
                  }
 | 
						|
                } else {
 | 
						|
                  if (EditValue >= Minimum + Step) {
 | 
						|
                    EditValue = EditValue - Step;
 | 
						|
                  } else if (EditValue > Minimum) {
 | 
						|
                    EditValue = Minimum;
 | 
						|
                  } else {
 | 
						|
                    EditValue = Maximum;
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              } else if (Key.ScanCode == SCAN_RIGHT) {
 | 
						|
                if (IntInput) {
 | 
						|
                  if ((INT64)EditValue + (INT64)Step <= (INT64)Maximum) {
 | 
						|
                    EditValue = EditValue + Step;
 | 
						|
                  } else if ((INT64)EditValue < (INT64)Maximum) {
 | 
						|
                    EditValue = Maximum;
 | 
						|
                  } else {
 | 
						|
                    EditValue = Minimum;
 | 
						|
                  }
 | 
						|
                } else {
 | 
						|
                  if (EditValue + Step <= Maximum) {
 | 
						|
                    EditValue = EditValue + Step;
 | 
						|
                  } else if (EditValue < Maximum) {
 | 
						|
                    EditValue = Maximum;
 | 
						|
                  } else {
 | 
						|
                    EditValue = Minimum;
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
 | 
						|
              ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
 | 
						|
              if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
 | 
						|
                if (MenuOption->Sequence == 2) {
 | 
						|
                  //
 | 
						|
                  // Year
 | 
						|
                  //
 | 
						|
                  UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16)EditValue);
 | 
						|
                } else {
 | 
						|
                  //
 | 
						|
                  // Month/Day
 | 
						|
                  //
 | 
						|
                  UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
 | 
						|
                }
 | 
						|
 | 
						|
                if (MenuOption->Sequence == 0) {
 | 
						|
                  ASSERT (EraseLen >= 2);
 | 
						|
                  FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
 | 
						|
                } else if (MenuOption->Sequence == 1) {
 | 
						|
                  ASSERT (EraseLen >= 1);
 | 
						|
                  FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
 | 
						|
                }
 | 
						|
              } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
 | 
						|
                UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
 | 
						|
 | 
						|
                if (MenuOption->Sequence == 0) {
 | 
						|
                  ASSERT (EraseLen >= 2);
 | 
						|
                  FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
 | 
						|
                } else if (MenuOption->Sequence == 1) {
 | 
						|
                  ASSERT (EraseLen >= 1);
 | 
						|
                  FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
 | 
						|
                }
 | 
						|
              } else {
 | 
						|
                QuestionValue->Value.u64 = EditValue;
 | 
						|
                PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
 | 
						|
              }
 | 
						|
 | 
						|
              gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
 | 
						|
              for (Loop = 0; Loop < EraseLen; Loop++) {
 | 
						|
                PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
 | 
						|
              }
 | 
						|
 | 
						|
              gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
 | 
						|
 | 
						|
              if (MenuOption->Sequence == 0) {
 | 
						|
                PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
 | 
						|
                Column = MenuOption->OptCol + 1;
 | 
						|
              }
 | 
						|
 | 
						|
              PrintStringAt (Column, Row, FormattedNumber);
 | 
						|
 | 
						|
              if (!DateOrTime || (MenuOption->Sequence == 2)) {
 | 
						|
                PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            goto EnterCarriageReturn;
 | 
						|
 | 
						|
          case SCAN_UP:
 | 
						|
          case SCAN_DOWN:
 | 
						|
            goto EnterCarriageReturn;
 | 
						|
 | 
						|
          case SCAN_ESC:
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
          default:
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
EnterCarriageReturn:
 | 
						|
 | 
						|
      case CHAR_CARRIAGE_RETURN:
 | 
						|
        //
 | 
						|
        // Validate input value with Minimum value.
 | 
						|
        //
 | 
						|
        ValidateFail = FALSE;
 | 
						|
        if (IntInput) {
 | 
						|
          //
 | 
						|
          // After user input Enter, need to check whether the input value.
 | 
						|
          // If input a negative value, should compare with maximum value.
 | 
						|
          // else compare with the minimum value.
 | 
						|
          //
 | 
						|
          if (Negative) {
 | 
						|
            ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
 | 
						|
          } else {
 | 
						|
            ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (ValidateFail) {
 | 
						|
            UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        } else if (EditValue < Minimum) {
 | 
						|
          UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        UpdateStatusBar (INPUT_ERROR, FALSE);
 | 
						|
        CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
 | 
						|
        QuestionValue = &gUserInput->InputValue;
 | 
						|
        //
 | 
						|
        // Store Edit value back to Question
 | 
						|
        //
 | 
						|
        if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
 | 
						|
          switch (MenuOption->Sequence) {
 | 
						|
            case 0:
 | 
						|
              QuestionValue->Value.date.Month = (UINT8)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            case 1:
 | 
						|
              QuestionValue->Value.date.Day = (UINT8)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            case 2:
 | 
						|
              QuestionValue->Value.date.Year = (UINT16)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            default:
 | 
						|
              break;
 | 
						|
          }
 | 
						|
        } else if (Question->OpCode->OpCode  == EFI_IFR_TIME_OP) {
 | 
						|
          switch (MenuOption->Sequence) {
 | 
						|
            case 0:
 | 
						|
              QuestionValue->Value.time.Hour = (UINT8)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            case 1:
 | 
						|
              QuestionValue->Value.time.Minute = (UINT8)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            case 2:
 | 
						|
              QuestionValue->Value.time.Second = (UINT8)EditValue;
 | 
						|
              break;
 | 
						|
 | 
						|
            default:
 | 
						|
              break;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Numeric
 | 
						|
          //
 | 
						|
          QuestionValue->Value.u64 = EditValue;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Adjust the value to the correct one.
 | 
						|
        // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
 | 
						|
        //              2013.03.29 -> 2013.02.29 -> 2013.02.28
 | 
						|
        //
 | 
						|
        if ((Question->OpCode->OpCode  == EFI_IFR_DATE_OP) &&
 | 
						|
            ((MenuOption->Sequence == 0) || (MenuOption->Sequence == 2)))
 | 
						|
        {
 | 
						|
          AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
 | 
						|
        }
 | 
						|
 | 
						|
        return EFI_SUCCESS;
 | 
						|
 | 
						|
      case CHAR_BACKSPACE:
 | 
						|
        if (ManualInput) {
 | 
						|
          if (Count == 0) {
 | 
						|
            if (Negative) {
 | 
						|
              Negative = FALSE;
 | 
						|
              Column--;
 | 
						|
              PrintStringAt (Column, Row, L" ");
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Remove a character
 | 
						|
          //
 | 
						|
          EditValue = PreviousNumber[Count - 1];
 | 
						|
          UpdateStatusBar (INPUT_ERROR, FALSE);
 | 
						|
          Count--;
 | 
						|
          Column--;
 | 
						|
          PrintStringAt (Column, Row, L" ");
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        if (ManualInput) {
 | 
						|
          if (HexInput) {
 | 
						|
            if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
 | 
						|
              Digital = (UINT8)(Key.UnicodeChar - L'0');
 | 
						|
            } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
 | 
						|
              Digital = (UINT8)(Key.UnicodeChar - L'A' + 0x0A);
 | 
						|
            } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
 | 
						|
              Digital = (UINT8)(Key.UnicodeChar - L'a' + 0x0A);
 | 
						|
            } else {
 | 
						|
              UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            if ((Key.UnicodeChar > L'9') || (Key.UnicodeChar < L'0')) {
 | 
						|
              UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // If Count exceed input width, there is no way more is valid
 | 
						|
          //
 | 
						|
          if (Count >= InputWidth) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Someone typed something valid!
 | 
						|
          //
 | 
						|
          if (Count != 0) {
 | 
						|
            if (HexInput) {
 | 
						|
              EditValue = LShiftU64 (EditValue, 4) + Digital;
 | 
						|
            } else if (IntInput && Negative) {
 | 
						|
              //
 | 
						|
              // Save the negative number.
 | 
						|
              //
 | 
						|
              EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;
 | 
						|
            } else {
 | 
						|
              EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            if (HexInput) {
 | 
						|
              EditValue = Digital;
 | 
						|
            } else if (IntInput && Negative) {
 | 
						|
              //
 | 
						|
              // Save the negative number.
 | 
						|
              //
 | 
						|
              EditValue = ~(Key.UnicodeChar - L'0') + 1;
 | 
						|
            } else {
 | 
						|
              EditValue = Key.UnicodeChar - L'0';
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          if (IntInput) {
 | 
						|
            ValidateFail = FALSE;
 | 
						|
            //
 | 
						|
            // When user input a new value, should check the current value.
 | 
						|
            // If user input a negative value, should compare it with minimum
 | 
						|
            // value, else compare it with maximum value.
 | 
						|
            //
 | 
						|
            if (Negative) {
 | 
						|
              ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
 | 
						|
            } else {
 | 
						|
              ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
 | 
						|
            }
 | 
						|
 | 
						|
            if (ValidateFail) {
 | 
						|
              UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
              ASSERT (Count < ARRAY_SIZE (PreviousNumber));
 | 
						|
              EditValue = PreviousNumber[Count];
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            if (EditValue > Maximum) {
 | 
						|
              UpdateStatusBar (INPUT_ERROR, TRUE);
 | 
						|
              ASSERT (Count < ARRAY_SIZE (PreviousNumber));
 | 
						|
              EditValue = PreviousNumber[Count];
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          UpdateStatusBar (INPUT_ERROR, FALSE);
 | 
						|
 | 
						|
          Count++;
 | 
						|
          ASSERT (Count < (ARRAY_SIZE (PreviousNumber)));
 | 
						|
          PreviousNumber[Count] = EditValue;
 | 
						|
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
 | 
						|
          PrintCharAt (Column, Row, Key.UnicodeChar);
 | 
						|
          Column++;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } while (TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Adjust option order base on the question value.
 | 
						|
 | 
						|
  @param  Question           Pointer to current question.
 | 
						|
  @param  PopUpMenuLines     The line number of the pop up menu.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If Option input is processed successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AdjustOptionOrder (
 | 
						|
  IN  FORM_DISPLAY_ENGINE_STATEMENT  *Question,
 | 
						|
  OUT UINTN                          *PopUpMenuLines
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                    Index;
 | 
						|
  EFI_IFR_ORDERED_LIST     *OrderList;
 | 
						|
  UINT8                    *ValueArray;
 | 
						|
  UINT8                    ValueType;
 | 
						|
  LIST_ENTRY               *Link;
 | 
						|
  DISPLAY_QUESTION_OPTION  *OneOfOption;
 | 
						|
  EFI_HII_VALUE            *HiiValueArray;
 | 
						|
 | 
						|
  Link        = GetFirstNode (&Question->OptionListHead);
 | 
						|
  OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
  ValueArray  = Question->CurrentValue.Buffer;
 | 
						|
  ValueType   =  OneOfOption->OptionOpCode->Type;
 | 
						|
  OrderList   = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
 | 
						|
 | 
						|
  for (Index = 0; Index < OrderList->MaxContainers; Index++) {
 | 
						|
    if (GetArrayData (ValueArray, ValueType, Index) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *PopUpMenuLines = Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Prepare HiiValue array
 | 
						|
  //
 | 
						|
  HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));
 | 
						|
  ASSERT (HiiValueArray != NULL);
 | 
						|
 | 
						|
  for (Index = 0; Index < *PopUpMenuLines; Index++) {
 | 
						|
    HiiValueArray[Index].Type      = ValueType;
 | 
						|
    HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < *PopUpMenuLines; Index++) {
 | 
						|
    OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);
 | 
						|
    if (OneOfOption == NULL) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    RemoveEntryList (&OneOfOption->Link);
 | 
						|
 | 
						|
    //
 | 
						|
    // Insert to head.
 | 
						|
    //
 | 
						|
    InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (HiiValueArray);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Base on the type to compare the value.
 | 
						|
 | 
						|
  @param  Value1                The first value need to compare.
 | 
						|
  @param  Value2                The second value need to compare.
 | 
						|
  @param  Type                  The value type for above two values.
 | 
						|
 | 
						|
  @retval TRUE                  The two value are same.
 | 
						|
  @retval FALSE                 The two value are different.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsValuesEqual (
 | 
						|
  IN EFI_IFR_TYPE_VALUE  *Value1,
 | 
						|
  IN EFI_IFR_TYPE_VALUE  *Value2,
 | 
						|
  IN UINT8               Type
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (Type) {
 | 
						|
    case EFI_IFR_TYPE_BOOLEAN:
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_8:
 | 
						|
      return (BOOLEAN)(Value1->u8 == Value2->u8);
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_16:
 | 
						|
      return (BOOLEAN)(Value1->u16 == Value2->u16);
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_32:
 | 
						|
      return (BOOLEAN)(Value1->u32 == Value2->u32);
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_64:
 | 
						|
      return (BOOLEAN)(Value1->u64 == Value2->u64);
 | 
						|
 | 
						|
    default:
 | 
						|
      ASSERT (FALSE);
 | 
						|
      return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Base on the type to set the value.
 | 
						|
 | 
						|
  @param  Dest                  The dest value.
 | 
						|
  @param  Source                The source value.
 | 
						|
  @param  Type                  The value type for above two values.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetValuesByType (
 | 
						|
  OUT EFI_IFR_TYPE_VALUE  *Dest,
 | 
						|
  IN  EFI_IFR_TYPE_VALUE  *Source,
 | 
						|
  IN  UINT8               Type
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (Type) {
 | 
						|
    case EFI_IFR_TYPE_BOOLEAN:
 | 
						|
      Dest->b = Source->b;
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_8:
 | 
						|
      Dest->u8 = Source->u8;
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_16:
 | 
						|
      Dest->u16 = Source->u16;
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_32:
 | 
						|
      Dest->u32 = Source->u32;
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IFR_TYPE_NUM_SIZE_64:
 | 
						|
      Dest->u64 = Source->u64;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      ASSERT (FALSE);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get selection for OneOf and OrderedList (Left/Right will be ignored).
 | 
						|
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If Option input is processed successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetSelectionInputPopUp (
 | 
						|
  IN  UI_MENU_OPTION  *MenuOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_INPUT_KEY                  Key;
 | 
						|
  UINTN                          Index;
 | 
						|
  CHAR16                         *StringPtr;
 | 
						|
  CHAR16                         *TempStringPtr;
 | 
						|
  UINTN                          Index2;
 | 
						|
  UINTN                          TopOptionIndex;
 | 
						|
  UINTN                          HighlightOptionIndex;
 | 
						|
  UINTN                          Start;
 | 
						|
  UINTN                          End;
 | 
						|
  UINTN                          Top;
 | 
						|
  UINTN                          Bottom;
 | 
						|
  UINTN                          PopUpMenuLines;
 | 
						|
  UINTN                          MenuLinesInView;
 | 
						|
  UINTN                          PopUpWidth;
 | 
						|
  CHAR16                         Character;
 | 
						|
  INT32                          SavedAttribute;
 | 
						|
  BOOLEAN                        ShowDownArrow;
 | 
						|
  BOOLEAN                        ShowUpArrow;
 | 
						|
  UINTN                          DimensionsWidth;
 | 
						|
  LIST_ENTRY                     *Link;
 | 
						|
  BOOLEAN                        OrderedList;
 | 
						|
  UINT8                          *ValueArray;
 | 
						|
  UINT8                          *ReturnValue;
 | 
						|
  UINT8                          ValueType;
 | 
						|
  EFI_HII_VALUE                  HiiValue;
 | 
						|
  DISPLAY_QUESTION_OPTION        *OneOfOption;
 | 
						|
  DISPLAY_QUESTION_OPTION        *CurrentOption;
 | 
						|
  FORM_DISPLAY_ENGINE_STATEMENT  *Question;
 | 
						|
  INTN                           Result;
 | 
						|
  EFI_IFR_ORDERED_LIST           *OrderList;
 | 
						|
 | 
						|
  DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
 | 
						|
 | 
						|
  ValueArray    = NULL;
 | 
						|
  ValueType     = 0;
 | 
						|
  CurrentOption = NULL;
 | 
						|
  ShowDownArrow = FALSE;
 | 
						|
  ShowUpArrow   = FALSE;
 | 
						|
 | 
						|
  ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));
 | 
						|
 | 
						|
  Question = MenuOption->ThisTag;
 | 
						|
  if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
 | 
						|
    Link        = GetFirstNode (&Question->OptionListHead);
 | 
						|
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
    ValueArray  = Question->CurrentValue.Buffer;
 | 
						|
    ValueType   =  OneOfOption->OptionOpCode->Type;
 | 
						|
    OrderedList = TRUE;
 | 
						|
    OrderList   = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
 | 
						|
  } else {
 | 
						|
    OrderedList = FALSE;
 | 
						|
    OrderList   = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate Option count
 | 
						|
  //
 | 
						|
  PopUpMenuLines = 0;
 | 
						|
  if (OrderedList) {
 | 
						|
    AdjustOptionOrder (Question, &PopUpMenuLines);
 | 
						|
  } else {
 | 
						|
    Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
    while (!IsNull (&Question->OptionListHead, Link)) {
 | 
						|
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
      PopUpMenuLines++;
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the number of one of options present and its size
 | 
						|
  //
 | 
						|
  PopUpWidth           = 0;
 | 
						|
  HighlightOptionIndex = 0;
 | 
						|
  Link                 = GetFirstNode (&Question->OptionListHead);
 | 
						|
  for (Index = 0; Index < PopUpMenuLines; Index++) {
 | 
						|
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
 | 
						|
    StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
 | 
						|
    if (StrLen (StringPtr) > PopUpWidth) {
 | 
						|
      PopUpWidth = StrLen (StringPtr);
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (StringPtr);
 | 
						|
    HiiValue.Type = OneOfOption->OptionOpCode->Type;
 | 
						|
    SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
 | 
						|
    if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
 | 
						|
      //
 | 
						|
      // Find current selected Option for OneOf
 | 
						|
      //
 | 
						|
      HighlightOptionIndex = Index;
 | 
						|
    }
 | 
						|
 | 
						|
    Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Perform popup menu initialization.
 | 
						|
  //
 | 
						|
  PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
 | 
						|
 | 
						|
  SavedAttribute = gST->ConOut->Mode->Attribute;
 | 
						|
  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
 | 
						|
 | 
						|
  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
 | 
						|
    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
 | 
						|
  }
 | 
						|
 | 
						|
  Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
 | 
						|
  End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
 | 
						|
  Top    = gStatementDimensions.TopRow;
 | 
						|
  Bottom = gStatementDimensions.BottomRow - 1;
 | 
						|
 | 
						|
  MenuLinesInView = Bottom - Top - 1;
 | 
						|
  if (MenuLinesInView >= PopUpMenuLines) {
 | 
						|
    Top    = Top + (MenuLinesInView - PopUpMenuLines) / 2;
 | 
						|
    Bottom = Top + PopUpMenuLines + 1;
 | 
						|
  } else {
 | 
						|
    ShowDownArrow = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
 | 
						|
    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
 | 
						|
  } else {
 | 
						|
    TopOptionIndex = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // Clear that portion of the screen
 | 
						|
    //
 | 
						|
    ClearLines (Start, End, Top, Bottom, GetPopupColor ());
 | 
						|
 | 
						|
    //
 | 
						|
    // Draw "One of" pop-up menu
 | 
						|
    //
 | 
						|
    Character = BOXDRAW_DOWN_RIGHT;
 | 
						|
    PrintCharAt (Start, Top, Character);
 | 
						|
    for (Index = Start; Index + 2 < End; Index++) {
 | 
						|
      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
 | 
						|
        Character = GEOMETRICSHAPE_UP_TRIANGLE;
 | 
						|
      } else {
 | 
						|
        Character = BOXDRAW_HORIZONTAL;
 | 
						|
      }
 | 
						|
 | 
						|
      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_DOWN_LEFT;
 | 
						|
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
 | 
						|
    Character = BOXDRAW_VERTICAL;
 | 
						|
    for (Index = Top + 1; Index < Bottom; Index++) {
 | 
						|
      PrintCharAt (Start, Index, Character);
 | 
						|
      PrintCharAt (End - 1, Index, Character);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Move to top Option
 | 
						|
    //
 | 
						|
    Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
    for (Index = 0; Index < TopOptionIndex; Index++) {
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Display the One of options
 | 
						|
    //
 | 
						|
    Index2 = Top + 1;
 | 
						|
    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
 | 
						|
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
      Link        = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
 | 
						|
      StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
 | 
						|
      ASSERT (StringPtr != NULL);
 | 
						|
      //
 | 
						|
      // If the string occupies multiple lines, truncate it to fit in one line,
 | 
						|
      // and append a "..." for indication.
 | 
						|
      //
 | 
						|
      if (StrLen (StringPtr) > (PopUpWidth - 1)) {
 | 
						|
        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
 | 
						|
        ASSERT (TempStringPtr != NULL);
 | 
						|
        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
 | 
						|
        FreePool (StringPtr);
 | 
						|
        StringPtr = TempStringPtr;
 | 
						|
        StrCatS (StringPtr, PopUpWidth - 1, L"...");
 | 
						|
      }
 | 
						|
 | 
						|
      if (Index == HighlightOptionIndex) {
 | 
						|
        //
 | 
						|
        // Highlight the selected one
 | 
						|
        //
 | 
						|
        CurrentOption = OneOfOption;
 | 
						|
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
 | 
						|
        PrintStringAt (Start + 2, Index2, StringPtr);
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
 | 
						|
      } else {
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
 | 
						|
        PrintStringAt (Start + 2, Index2, StringPtr);
 | 
						|
      }
 | 
						|
 | 
						|
      Index2++;
 | 
						|
      FreePool (StringPtr);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_UP_RIGHT;
 | 
						|
    PrintCharAt (Start, Bottom, Character);
 | 
						|
    for (Index = Start; Index + 2 < End; Index++) {
 | 
						|
      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
 | 
						|
        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
 | 
						|
      } else {
 | 
						|
        Character = BOXDRAW_HORIZONTAL;
 | 
						|
      }
 | 
						|
 | 
						|
      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_UP_LEFT;
 | 
						|
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
 | 
						|
 | 
						|
    //
 | 
						|
    // Get User selection
 | 
						|
    //
 | 
						|
    Key.UnicodeChar = CHAR_NULL;
 | 
						|
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
 | 
						|
      Key.ScanCode = gDirection;
 | 
						|
      gDirection   = 0;
 | 
						|
      goto TheKey;
 | 
						|
    }
 | 
						|
 | 
						|
    WaitForKeyStroke (&Key);
 | 
						|
 | 
						|
TheKey:
 | 
						|
    switch (Key.UnicodeChar) {
 | 
						|
      case '+':
 | 
						|
        if (OrderedList) {
 | 
						|
          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
 | 
						|
            //
 | 
						|
            // Highlight reaches the top of the popup window, scroll one menu item.
 | 
						|
            //
 | 
						|
            TopOptionIndex--;
 | 
						|
            ShowDownArrow = TRUE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (TopOptionIndex == 0) {
 | 
						|
            ShowUpArrow = FALSE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (HighlightOptionIndex > 0) {
 | 
						|
            HighlightOptionIndex--;
 | 
						|
 | 
						|
            ASSERT (CurrentOption != NULL);
 | 
						|
            SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case '-':
 | 
						|
        //
 | 
						|
        // If an ordered list op-code, we will allow for a popup of +/- keys
 | 
						|
        // to create an ordered list of items
 | 
						|
        //
 | 
						|
        if (OrderedList) {
 | 
						|
          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
 | 
						|
              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
 | 
						|
          {
 | 
						|
            //
 | 
						|
            // Highlight reaches the bottom of the popup window, scroll one menu item.
 | 
						|
            //
 | 
						|
            TopOptionIndex++;
 | 
						|
            ShowUpArrow = TRUE;
 | 
						|
          }
 | 
						|
 | 
						|
          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
 | 
						|
            ShowDownArrow = FALSE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
 | 
						|
            HighlightOptionIndex++;
 | 
						|
 | 
						|
            ASSERT (CurrentOption != NULL);
 | 
						|
            SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case CHAR_NULL:
 | 
						|
        switch (Key.ScanCode) {
 | 
						|
          case SCAN_UP:
 | 
						|
          case SCAN_DOWN:
 | 
						|
            if (Key.ScanCode == SCAN_UP) {
 | 
						|
              if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
 | 
						|
                //
 | 
						|
                // Highlight reaches the top of the popup window, scroll one menu item.
 | 
						|
                //
 | 
						|
                TopOptionIndex--;
 | 
						|
                ShowDownArrow = TRUE;
 | 
						|
              }
 | 
						|
 | 
						|
              if (TopOptionIndex == 0) {
 | 
						|
                ShowUpArrow = FALSE;
 | 
						|
              }
 | 
						|
 | 
						|
              if (HighlightOptionIndex > 0) {
 | 
						|
                HighlightOptionIndex--;
 | 
						|
              }
 | 
						|
            } else {
 | 
						|
              if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
 | 
						|
                  (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
 | 
						|
              {
 | 
						|
                //
 | 
						|
                // Highlight reaches the bottom of the popup window, scroll one menu item.
 | 
						|
                //
 | 
						|
                TopOptionIndex++;
 | 
						|
                ShowUpArrow = TRUE;
 | 
						|
              }
 | 
						|
 | 
						|
              if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
 | 
						|
                ShowDownArrow = FALSE;
 | 
						|
              }
 | 
						|
 | 
						|
              if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
 | 
						|
                HighlightOptionIndex++;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
 | 
						|
          case SCAN_ESC:
 | 
						|
            gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
 | 
						|
 | 
						|
            //
 | 
						|
            // Restore link list order for orderedlist
 | 
						|
            //
 | 
						|
            if (OrderedList) {
 | 
						|
              HiiValue.Type      = ValueType;
 | 
						|
              HiiValue.Value.u64 = 0;
 | 
						|
              for (Index = 0; Index < OrderList->MaxContainers; Index++) {
 | 
						|
                HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
 | 
						|
                if (HiiValue.Value.u64 == 0) {
 | 
						|
                  break;
 | 
						|
                }
 | 
						|
 | 
						|
                OneOfOption = ValueToOption (Question, &HiiValue);
 | 
						|
                if (OneOfOption == NULL) {
 | 
						|
                  return EFI_NOT_FOUND;
 | 
						|
                }
 | 
						|
 | 
						|
                RemoveEntryList (&OneOfOption->Link);
 | 
						|
                InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
          default:
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case CHAR_CARRIAGE_RETURN:
 | 
						|
        //
 | 
						|
        // return the current selection
 | 
						|
        //
 | 
						|
        if (OrderedList) {
 | 
						|
          ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
 | 
						|
          ASSERT (ReturnValue != NULL);
 | 
						|
          Index = 0;
 | 
						|
          Link  = GetFirstNode (&Question->OptionListHead);
 | 
						|
          while (!IsNull (&Question->OptionListHead, Link)) {
 | 
						|
            OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
            Link        = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
 | 
						|
            SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);
 | 
						|
 | 
						|
            Index++;
 | 
						|
            if (Index > OrderList->MaxContainers) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
 | 
						|
            FreePool (ReturnValue);
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
          } else {
 | 
						|
            gUserInput->InputValue.Buffer    = ReturnValue;
 | 
						|
            gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          ASSERT (CurrentOption != NULL);
 | 
						|
          gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
 | 
						|
          if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
          } else {
 | 
						|
            SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
 | 
						|
 | 
						|
        return EFI_SUCCESS;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } while (TRUE);
 | 
						|
}
 |