/** Free resources of a Statement @param Statement Pointer of the Statement @return None. **/ VOID DestroyStatement ( IN OUT FORM_BROWSER_STATEMENT *Statement ) { LIST_ENTRY *Link; QUESTION_DEFAULT *Default; QUESTION_OPTION *Option; // // Free Default value List // while (!IsListEmpty (&Statement->DefaultListHead)) { Link = GetFirstNode (&Statement->DefaultListHead); Default = QUESTION_DEFAULT_FROM_LINK (Link); RemoveEntryList (&Default->Link); gBS->FreePool (Default); } // // Free Options List // while (!IsListEmpty (&Statement->OptionListHead)) { Link = GetFirstNode (&Statement->OptionListHead); Option = QUESTION_OPTION_FROM_LINK (Link); RemoveEntryList (&Option->Link); gBS->FreePool (Option); } }
/** Search an Option of a Question by its value. @param Question The Question @param OptionValue Value for Option to be searched. @retval Pointer Pointer to the found Option. @retval NULL Option not found. **/ QUESTION_OPTION * ValueToOption ( IN FORM_BROWSER_STATEMENT *Question, IN EFI_HII_VALUE *OptionValue ) { LIST_ENTRY *Link; QUESTION_OPTION *Option; INTN Result; Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { return Option; } Link = GetNextNode (&Question->OptionListHead, Link); } return NULL; }
QUESTION_OPTION * ValueToOption ( IN FORM_BROWSER_STATEMENT *Question, IN EFI_HII_VALUE *OptionValue ) /*++ Routine Description: Search an Option of a Question by its value. Arguments: Question - The Question OptionValue - Value for Option to be searched. Returns: Pointer - Pointer to the found Option. NULL - Option not found. --*/ { EFI_LIST_ENTRY *Link; QUESTION_OPTION *Option; Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) { return Option; } Link = GetNextNode (&Question->OptionListHead, Link); } return NULL; }
/** Process a Question's Option (whether selected or un-selected). @param Selection Pointer to UI_MENU_SELECTION. @param MenuOption The MenuOption for this Question. @param Selected TRUE: if Question is selected. @param OptionString Pointer of the Option String to be displayed. @retval EFI_SUCCESS Question Option process success. @retval Other Question Option process fail. **/ EFI_STATUS ProcessOptions ( IN UI_MENU_SELECTION *Selection, IN UI_MENU_OPTION *MenuOption, IN BOOLEAN Selected, OUT CHAR16 **OptionString ) { EFI_STATUS Status; CHAR16 *StringPtr; CHAR16 *TempString; UINTN Index; FORM_BROWSER_STATEMENT *Question; CHAR16 FormattedNumber[21]; UINT16 Number; CHAR16 Character[2]; EFI_INPUT_KEY Key; UINTN BufferSize; QUESTION_OPTION *OneOfOption; LIST_ENTRY *Link; EFI_HII_VALUE HiiValue; EFI_HII_VALUE *QuestionValue; BOOLEAN Suppress; UINT16 Maximum; QUESTION_OPTION *Option; UINTN Index2; UINT8 *ValueArray; UINT8 ValueType; EFI_STRING_ID StringId; Status = EFI_SUCCESS; StringPtr = NULL; Character[1] = L'\0'; *OptionString = NULL; StringId = 0; ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow; Question = MenuOption->ThisTag; QuestionValue = &Question->HiiValue; Maximum = (UINT16) Question->Maximum; ValueArray = Question->BufferValue; ValueType = Question->ValueType; switch (Question->Operand) { case EFI_IFR_ORDERED_LIST_OP: // // Check whether there are Options of this OrderedList // if (IsListEmpty (&Question->OptionListHead)) { break; } // // Initialize Option value array // if (GetArrayData (ValueArray, ValueType, 0) == 0) { GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0); } if (Selected) { // // Go ask for input // Status = GetSelectionInputPopUp (Selection, MenuOption); } else { // // We now know how many strings we will have, so we can allocate the // space required for the array or strings. // *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize); ASSERT (*OptionString); 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) { // // Values for the options in ordered lists should never be a 0 // break; } OneOfOption = ValueToOption (Question, &HiiValue); if (OneOfOption == NULL) { // // Show error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); // // The initial value of the orderedlist is invalid, force to be valid value // Link = GetFirstNode (&Question->OptionListHead); Index2 = 0; while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) { Option = QUESTION_OPTION_FROM_LINK (Link); SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64); Index2++; Link = GetNextNode (&Question->OptionListHead, Link); } SetArrayData (ValueArray, ValueType, Index2, 0); Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); FreePool (*OptionString); *OptionString = NULL; return EFI_NOT_FOUND; } Suppress = FALSE; if ((OneOfOption->SuppressExpression != NULL) && (EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress)) { // // This option is suppressed // Suppress = TRUE; } if (!Suppress) { Character[0] = LEFT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); StringPtr = GetToken (OneOfOption->Text, Selection->Handle); ASSERT (StringPtr != NULL); NewStrCat (OptionString[0], StringPtr); Character[0] = RIGHT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); Character[0] = CHAR_CARRIAGE_RETURN; NewStrCat (OptionString[0], Character); FreePool (StringPtr); } } } break; case EFI_IFR_ONE_OF_OP: // // Check whether there are Options of this OneOf // if (IsListEmpty (&Question->OptionListHead)) { break; } if (Selected) { // // Go ask for input // Status = GetSelectionInputPopUp (Selection, MenuOption); } else { *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); OneOfOption = ValueToOption (Question, QuestionValue); if (OneOfOption == NULL) { // // Show error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); // // Force the Question value to be valid // Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); if ((Option->SuppressExpression == NULL) || (EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)) { CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); break; } Link = GetNextNode (&Question->OptionListHead, Link); } FreePool (*OptionString); *OptionString = NULL; return EFI_NOT_FOUND; } if ((OneOfOption->SuppressExpression != NULL) && ((EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) { // // This option is suppressed // Suppress = TRUE; } else { Suppress = FALSE; } if (Suppress) { // // Current selected option happen to be suppressed, // enforce to select on a non-suppressed option // Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { OneOfOption = QUESTION_OPTION_FROM_LINK (Link); if ((OneOfOption->SuppressExpression == NULL) || (EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)) { Suppress = FALSE; CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND); break; } Link = GetNextNode (&Question->OptionListHead, Link); } } if (!Suppress) { Character[0] = LEFT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); StringPtr = GetToken (OneOfOption->Text, Selection->Handle); ASSERT (StringPtr != NULL); NewStrCat (OptionString[0], StringPtr); Character[0] = RIGHT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); FreePool (StringPtr); } } break; case EFI_IFR_CHECKBOX_OP: *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); *OptionString[0] = LEFT_CHECKBOX_DELIMITER; if (Selected) { // // Since this is a BOOLEAN operation, flip it upon selection // QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); // // Perform inconsistent check // Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); if (EFI_ERROR (Status)) { // // Inconsistent check fail, restore Question Value // QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); FreePool (*OptionString); *OptionString = NULL; return Status; } // // Save Question value // Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); } if (QuestionValue->Value.b) { *(OptionString[0] + 1) = CHECK_ON; } else { *(OptionString[0] + 1) = CHECK_OFF; } *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; break; case EFI_IFR_NUMERIC_OP: if (Selected) { // // Go ask for input // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); *OptionString[0] = LEFT_NUMERIC_DELIMITER; // // Formatted print // PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); Number = (UINT16) GetStringWidth (FormattedNumber); CopyMem (OptionString[0] + 1, FormattedNumber, Number); *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; } break; case EFI_IFR_DATE_OP: if (Selected) { // // This is similar to numerics // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); switch (MenuOption->Sequence) { case 0: *OptionString[0] = LEFT_NUMERIC_DELIMITER; UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); *(OptionString[0] + 3) = DATE_SEPARATOR; break; case 1: SetUnicodeMem (OptionString[0], 4, L' '); UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); *(OptionString[0] + 6) = DATE_SEPARATOR; break; case 2: SetUnicodeMem (OptionString[0], 7, L' '); UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year); *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; break; } } break; case EFI_IFR_TIME_OP: if (Selected) { // // This is similar to numerics // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); switch (MenuOption->Sequence) { case 0: *OptionString[0] = LEFT_NUMERIC_DELIMITER; UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); *(OptionString[0] + 3) = TIME_SEPARATOR; break; case 1: SetUnicodeMem (OptionString[0], 4, L' '); UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); *(OptionString[0] + 6) = TIME_SEPARATOR; break; case 2: SetUnicodeMem (OptionString[0], 7, L' '); UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; break; } } break; case EFI_IFR_STRING_OP: if (Selected) { StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (StringPtr); CopyMem(StringPtr, Question->BufferValue, Maximum * sizeof (CHAR16)); Status = ReadString (MenuOption, gPromptForData, StringPtr); if (!EFI_ERROR (Status)) { HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL); Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); if (EFI_ERROR (Status)) { HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); } else { CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); } } FreePool (StringPtr); } else { *OptionString = AllocateZeroPool (BufferSize); ASSERT (*OptionString); if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) { *(OptionString[0]) = '_'; } else { if ((Maximum * sizeof (CHAR16)) < BufferSize) { BufferSize = Maximum * sizeof (CHAR16); } CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize); } } break; case EFI_IFR_PASSWORD_OP: if (Selected) { StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (StringPtr); // // For interactive passwords, old password is validated by callback // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { // // Use a NULL password to test whether old password is required // *StringPtr = 0; Status = PasswordCallback (Selection, MenuOption, StringPtr); if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) { // // Callback is not supported, or // Callback request to terminate password input // FreePool (StringPtr); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { // // Old password exist, ask user for the old password // Status = ReadString (MenuOption, gPromptForPassword, StringPtr); if (EFI_ERROR (Status)) { FreePool (StringPtr); return Status; } // // Check user input old password // Status = PasswordCallback (Selection, MenuOption, StringPtr); if (EFI_ERROR (Status)) { if (Status == EFI_NOT_READY) { // // Typed in old password incorrect // PasswordInvalid (); } else { Status = EFI_SUCCESS; } FreePool (StringPtr); return Status; } } } else { // // For non-interactive password, validate old password in local // if (*((CHAR16 *) Question->BufferValue) != 0) { // // There is something there! Prompt for password // Status = ReadString (MenuOption, gPromptForPassword, StringPtr); if (EFI_ERROR (Status)) { FreePool (StringPtr); return Status; } TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue); ASSERT (TempString != NULL); TempString[Maximum] = L'\0'; if (StrCmp (StringPtr, TempString) != 0) { // // Typed in old password incorrect // PasswordInvalid (); FreePool (StringPtr); FreePool (TempString); return Status; } FreePool (TempString); } } // // Ask for new password // ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); if (EFI_ERROR (Status)) { // // Reset state machine for interactive password // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } FreePool (StringPtr); return Status; } // // Confirm new password // TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (TempString); Status = ReadString (MenuOption, gConfirmPassword, TempString); if (EFI_ERROR (Status)) { // // Reset state machine for interactive password // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } FreePool (StringPtr); FreePool (TempString); return Status; } // // Compare two typed-in new passwords // if (StrCmp (StringPtr, TempString) == 0) { // // Prepare the Question->HiiValue.Value.string for ValidateQuestion use. // if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { StringId = Question->HiiValue.Value.string; Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle); } else { HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL); } Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); // // Researve the Question->HiiValue.Value.string. // if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle); Question->HiiValue.Value.string = StringId; } if (EFI_ERROR (Status)) { // // Reset state machine for interactive password // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } else { // // Researve the Question->HiiValue.Value.string. // HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); } } else { // // Two password match, send it to Configuration Driver // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, StringPtr); } else { CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); } } } else { // // Reset state machine for interactive password // if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } // // Two password mismatch, prompt error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); } FreePool (TempString); FreePool (StringPtr); } break; default: break; } return Status; }
/** 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); }
/** Get question default value, and set it into the match var storage. Note Framework 0.92's HII Implementation does not support for default value for these opcodes: EFI_IFR_ORDERED_LIST_OP: EFI_IFR_PASSWORD_OP: EFI_IFR_STRING_OP: @param Question Question to be set to its default value. @param DefaultId The Class of the default. @param VarStoreId Id of var storage. @param Node Var storage buffer to store the got default value. @retval EFI_SUCCESS Question is reset to default value. **/ EFI_STATUS GetQuestionDefault ( IN FORM_BROWSER_STATEMENT *Question, IN UINT16 DefaultId, IN UINT16 VarStoreId, OUT UEFI_IFR_BUFFER_STORAGE_NODE *Node ) { EFI_STATUS Status; LIST_ENTRY *Link; QUESTION_DEFAULT *Default; QUESTION_OPTION *Option; EFI_HII_VALUE *HiiValue; Status = EFI_SUCCESS; // // Statement don't have storage, skip them // if (Question->QuestionId == 0) { return Status; } if (Question->VarStoreId != VarStoreId) { return Status; } ASSERT (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER); // // There are three ways to specify default value for a Question: // 1, use nested EFI_IFR_DEFAULT (highest priority) // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) // HiiValue = &Question->HiiValue; // // EFI_IFR_DEFAULT has highest priority // if (!IsListEmpty (&Question->DefaultListHead)) { Link = GetFirstNode (&Question->DefaultListHead); while (!IsNull (&Question->DefaultListHead, Link)) { Default = QUESTION_DEFAULT_FROM_LINK (Link); if (Default->DefaultId == DefaultId) { // // Default value is embedded in EFI_IFR_DEFAULT // CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); return EFI_SUCCESS; } Link = GetNextNode (&Question->DefaultListHead, Link); } } // // EFI_ONE_OF_OPTION // if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { // // OneOfOption could only provide Standard and Manufacturing default // Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT)) || ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) ) { CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); return EFI_SUCCESS; } Link = GetNextNode (&Question->OptionListHead, Link); } } } // // EFI_IFR_CHECKBOX - lowest priority // if (Question->Operand == EFI_IFR_CHECKBOX_OP) { if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { // // Checkbox could only provide Standard and Manufacturing default // if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT)) || ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG)) ) { HiiValue->Value.b = TRUE; } else { HiiValue->Value.b = FALSE; } SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); return EFI_SUCCESS; } } return Status; }