示例#1
0
/**
  Swap two image records.

  @param  FirstImageRecord   first image record.
  @param  SecondImageRecord  second image record.
**/
STATIC
VOID
SwapImageRecord (
  IN IMAGE_PROPERTIES_RECORD      *FirstImageRecord,
  IN IMAGE_PROPERTIES_RECORD      *SecondImageRecord
  )
{
  IMAGE_PROPERTIES_RECORD      TempImageRecord;

  TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
  TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
  TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;

  FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
  FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
  FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;

  SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
  SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
  SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;

  SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
}
示例#2
0
/**
  Get selection for OneOf and OrderedList (Left/Right will be ignored).

  @param  Selection         Pointer to current selection.
  @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_SELECTION           *Selection,
    IN  UI_MENU_OPTION              *MenuOption
)
{
    EFI_STATUS              Status;
    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                   ValueType;
    EFI_HII_VALUE           HiiValue;
    EFI_HII_VALUE           *HiiValueArray;
    UINTN                   OptionCount;
    QUESTION_OPTION         *OneOfOption;
    QUESTION_OPTION         *CurrentOption;
    FORM_BROWSER_STATEMENT  *Question;
    INTN                    Result;

    DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;

    ValueArray        = NULL;
    ValueType         = 0;
    CurrentOption     = NULL;
    ShowDownArrow     = FALSE;
    ShowUpArrow       = FALSE;

    StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
    ASSERT (StringPtr);

    Question = MenuOption->ThisTag;
    if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
        ValueArray = Question->BufferValue;
        ValueType = Question->ValueType;
        OrderedList = TRUE;
    } else {
        OrderedList = FALSE;
    }

    //
    // Calculate Option count
    //
    if (OrderedList) {
        for (Index = 0; Index < Question->MaxContainers; Index++) {
            if (GetArrayData (ValueArray, ValueType, Index) == 0) {
                break;
            }
        }

        OptionCount = Index;
    } else {
        OptionCount = 0;
        Link = GetFirstNode (&Question->OptionListHead);
        while (!IsNull (&Question->OptionListHead, Link)) {
            OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

            OptionCount++;

            Link = GetNextNode (&Question->OptionListHead, Link);
        }
    }

    //
    // Prepare HiiValue array
    //
    HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
    ASSERT (HiiValueArray != NULL);
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < OptionCount; Index++) {
        if (OrderedList) {
            HiiValueArray[Index].Type = ValueType;
            HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
        } else {
            OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
            CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));
            Link = GetNextNode (&Question->OptionListHead, Link);
        }
    }

    //
    // Move Suppressed Option to list tail
    //
    PopUpMenuLines = 0;
    for (Index = 0; Index < OptionCount; Index++) {
        OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
        if (OneOfOption == NULL) {
            return EFI_NOT_FOUND;
        }

        RemoveEntryList (&OneOfOption->Link);

        if ((OneOfOption->SuppressExpression != NULL) &&
                EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
            //
            // This option is suppressed, insert to tail
            //
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
        } else {
            //
            // Insert to head
            //
            InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);

            PopUpMenuLines++;
        }
    }

    //
    // 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 = QUESTION_OPTION_FROM_LINK (Link);

        StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
        if (StrLen (StringPtr) > PopUpWidth) {
            PopUpWidth = StrLen (StringPtr);
        }
        FreePool (StringPtr);

        if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &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, POPUP_TEXT | POPUP_BACKGROUND);

    if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
        PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
    }

    Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
    End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
    Top    = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
    Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 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, POPUP_TEXT | POPUP_BACKGROUND);

        //
        // 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;
            }

            PrintChar (Character);
        }

        Character = BOXDRAW_DOWN_LEFT;
        PrintChar (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 = QUESTION_OPTION_FROM_LINK (Link);
            Link = GetNextNode (&Question->OptionListHead, Link);

            StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
            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;
                StrCat (StringPtr, L"...");
            }

            if (Index == HighlightOptionIndex) {
                //
                // Highlight the selected one
                //
                CurrentOption = OneOfOption;

                gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
                PrintStringAt (Start + 2, Index2, StringPtr);
                gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
            } else {
                gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
                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;
            }

            PrintChar (Character);
        }

        Character = BOXDRAW_UP_LEFT;
        PrintChar (Character);

        //
        // Get User selection
        //
        Key.UnicodeChar = CHAR_NULL;
        if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
            Key.ScanCode  = gDirection;
            gDirection    = 0;
            goto TheKey;
        }

        Status = 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 < Question->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);
                    }
                }

                FreePool (HiiValueArray);
                return EFI_DEVICE_ERROR;

            default:
                break;
            }

            break;

        case CHAR_CARRIAGE_RETURN:
            //
            // return the current selection
            //
            if (OrderedList) {
                Index = 0;
                Link = GetFirstNode (&Question->OptionListHead);
                while (!IsNull (&Question->OptionListHead, Link)) {
                    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

                    SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);

                    Index++;
                    if (Index > Question->MaxContainers) {
                        break;
                    }

                    Link = GetNextNode (&Question->OptionListHead, Link);
                }
            } else {
                ASSERT (CurrentOption != NULL);
                CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
            }

            gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
            FreePool (HiiValueArray);

            Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
            if (EFI_ERROR (Status)) {
                //
                // Input value is not valid, restore Question Value
                //
                GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
            } else {
                SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
                UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
            }

            return Status;

        default:
            break;
        }
    } while (TRUE);

}
示例#3
0
/**
  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_STATUS              Status;
  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;

  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
  ASSERT (StringPtr);

  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;
        StrCat (StringPtr, 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;
    }

    Status = 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;
          Status = EFI_SUCCESS;
        }
      } 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);
          Status = EFI_SUCCESS;
        }
      }

      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

      return EFI_SUCCESS;
      
    default:
      break;
    }
  } while (TRUE);

}
示例#4
0
/**
  Reorder boot options

  Ask for the boot option to move and then move it when up or down arrows
  are pressed. This function is called when the user selects the "Reorder Boot
  Device Entries" entry in the boot manager menu.
  The order of the boot options in BootOptionList and in the UEFI BootOrder
  global variable are kept coherent until the user confirm his reordering (ie:
  he does not exit by pressing escape).

  @param[in]  BootOptionsList  List of the boot devices constructed in
                               BootMenuMain()

  @retval  EFI_SUCCESS   No error encountered.
  @retval  !EFI_SUCCESS  An error has occured either in the selection of the
                         boot option to move or while interacting with the user.

**/
STATIC
EFI_STATUS
BootMenuReorderBootOptions (
  IN LIST_ENTRY *BootOptionsList
  )
{
  EFI_STATUS              Status;
  BDS_LOAD_OPTION_ENTRY  *BootOptionEntry;
  LIST_ENTRY             *SelectedEntry;
  LIST_ENTRY             *PrevEntry;
  BOOLEAN                 Move;
  BOOLEAN                 Save;
  BOOLEAN                 Cancel;
  UINTN                   WaitIndex;
  EFI_INPUT_KEY           Key;
  LIST_ENTRY             *SecondEntry;
  UINTN                   BootOrderSize;
  UINT16                 *BootOrder;
  LIST_ENTRY             *Entry;
  UINTN                   Index;

  DisplayBootOptions (BootOptionsList);

  // Ask to select the boot option to move
  while (TRUE) {
    Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }

    SelectedEntry = &BootOptionEntry->Link;
    SecondEntry = NULL;
    // Note down the previous entry in the list to be able to cancel changes
    PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);

    //  Start of interaction
    while (TRUE) {
      Print (
        L"* Use up/down arrows to move the entry '%s'",
        BootOptionEntry->BdsLoadOption->Description
        );

      // Wait for a move, save or cancel request
      Move   = FALSE;
      Save   = FALSE;
      Cancel = FALSE;
      do {
        Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
        if (!EFI_ERROR (Status)) {
          Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
        }
        if (EFI_ERROR (Status)) {
          Print (L"\n");
          goto ErrorExit;
        }

        switch (Key.ScanCode) {
        case SCAN_NULL:
          Save = (Key.UnicodeChar == CHAR_LINEFEED)        ||
                 (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||
                 (Key.UnicodeChar == 0x7f);
          break;

        case SCAN_UP:
          SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
          Move = SecondEntry != BootOptionsList;
          break;

        case SCAN_DOWN:
          SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);
          Move = SecondEntry != BootOptionsList;
          break;

        case SCAN_ESC:
          Cancel = TRUE;
          break;
        }
      } while ((!Move) && (!Save) && (!Cancel));

      if (Move) {
        if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {
          SwapListEntries (SelectedEntry, SecondEntry);
        }
      } else {
        if (Save) {
          Status = GetGlobalEnvironmentVariable (
                    L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder
                    );
          BootOrderSize /= sizeof (UINT16);

          if (!EFI_ERROR (Status)) {
            // The order of the boot options in the 'BootOptionsList' is the
            // new order that has been just defined by the user. Save this new
            // order in "BootOrder" UEFI global variable.
            Entry = GetFirstNode (BootOptionsList);
            for (Index = 0; Index < BootOrderSize; Index++) {
              BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;
              Entry = GetNextNode (BootOptionsList, Entry);
            }
            Status = gRT->SetVariable (
                           (CHAR16*)L"BootOrder",
                           &gEfiGlobalVariableGuid,
                           EFI_VARIABLE_NON_VOLATILE       |
                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
                           EFI_VARIABLE_RUNTIME_ACCESS,
                           BootOrderSize * sizeof (UINT16),
                           BootOrder
                           );
            FreePool (BootOrder);
          }

          if (EFI_ERROR (Status)) {
            Print (L"\nAn error occurred, move not completed!\n");
            Cancel = TRUE;
          }
        }

        if (Cancel) {
          //
          // Restore initial position of the selected boot option
          //
          RemoveEntryList (SelectedEntry);
          InsertHeadList (PrevEntry, SelectedEntry);
        }
      }

      Print (L"\n");
      DisplayBootOptions (BootOptionsList);
      // Saved or cancelled, back to the choice of boot option to move
      if (!Move) {
        break;
      }
    }
  }

ErrorExit:
  return Status ;
}