2 Implementation for handling the User Interface option processing.
5 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FormDisplay.h"
24 #define MAX_TIME_OUT_LEN 0x10
27 Concatenate a narrow string to another string.
29 @param Destination The destination string.
30 @param Source The source string. The string to be concatenated.
31 to the end of Destination.
36 IN OUT CHAR16
*Destination
,
42 for (Length
= 0; Destination
[Length
] != 0; Length
++)
46 // We now have the length of the original string
47 // We can safely assume for now that we are concatenating a narrow value to this string.
48 // For instance, the string is "XYZ" and cat'ing ">"
49 // If this assumption changes, we need to make this routine a bit more complex
51 Destination
[Length
] = NARROW_CHAR
;
54 StrCpy (Destination
+ Length
, Source
);
58 Compare two Hii value.
60 @param Value1 Expression value to compare on left-hand.
61 @param Value2 Expression value to compare on right-hand.
62 @param Result Return value after compare.
63 retval 0 Two operators equal.
64 return Positive value if Value1 is greater than Value2.
65 retval Negative value if Value1 is less than Value2.
66 @param HiiHandle Only required for string compare.
68 @retval other Could not perform compare on two values.
69 @retval EFI_SUCCESS Compare the value success.
74 IN EFI_HII_VALUE
*Value1
,
75 IN EFI_HII_VALUE
*Value2
,
77 IN EFI_HII_HANDLE HiiHandle OPTIONAL
85 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
86 if (Value1
->Type
!= EFI_IFR_TYPE_BUFFER
&& Value2
->Type
!= EFI_IFR_TYPE_BUFFER
) {
87 return EFI_UNSUPPORTED
;
91 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
92 if (Value1
->Type
!= Value2
->Type
) {
94 // Both Operator should be type of String
96 return EFI_UNSUPPORTED
;
99 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
101 // StringId 0 is reserved
103 return EFI_INVALID_PARAMETER
;
106 if (Value1
->Value
.string
== Value2
->Value
.string
) {
111 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
116 return EFI_NOT_FOUND
;
119 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
122 return EFI_NOT_FOUND
;
125 *Result
= StrCmp (Str1
, Str2
);
133 if (Value1
->Type
== EFI_IFR_TYPE_BUFFER
|| Value2
->Type
== EFI_IFR_TYPE_BUFFER
) {
134 if (Value1
->Type
!= Value2
->Type
) {
136 // Both Operator should be type of Buffer.
138 return EFI_UNSUPPORTED
;
140 Len
= Value1
->BufferLen
> Value2
->BufferLen
? Value2
->BufferLen
: Value1
->BufferLen
;
141 *Result
= CompareMem (Value1
->Buffer
, Value2
->Buffer
, Len
);
142 if ((*Result
== 0) && (Value1
->BufferLen
!= Value2
->BufferLen
))
145 // In this case, means base on samll number buffer, the data is same
146 // So which value has more data, which value is bigger.
148 *Result
= Value1
->BufferLen
> Value2
->BufferLen
? 1 : -1;
154 // Take remain types(integer, boolean, date/time) as integer
156 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
159 } else if (Temp64
< 0) {
169 Search an Option of a Question by its value.
171 @param Question The Question
172 @param OptionValue Value for Option to be searched.
174 @retval Pointer Pointer to the found Option.
175 @retval NULL Option not found.
178 DISPLAY_QUESTION_OPTION
*
180 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
181 IN EFI_HII_VALUE
*OptionValue
185 DISPLAY_QUESTION_OPTION
*Option
;
189 Link
= GetFirstNode (&Question
->OptionListHead
);
190 while (!IsNull (&Question
->OptionListHead
, Link
)) {
191 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
193 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
194 Value
.Type
= Option
->OptionOpCode
->Type
;
195 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
197 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
201 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
209 Return data element in an Array by its Index.
211 @param Array The data array.
212 @param Type Type of the data in this array.
213 @param Index Zero based index for data in this array.
215 @retval Value The data to be returned
227 ASSERT (Array
!= NULL
);
231 case EFI_IFR_TYPE_NUM_SIZE_8
:
232 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
235 case EFI_IFR_TYPE_NUM_SIZE_16
:
236 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
239 case EFI_IFR_TYPE_NUM_SIZE_32
:
240 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
243 case EFI_IFR_TYPE_NUM_SIZE_64
:
244 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
256 Set value of a data element in an Array by its Index.
258 @param Array The data array.
259 @param Type Type of the data in this array.
260 @param Index Zero based index for data in this array.
261 @param Value The value to be set.
273 ASSERT (Array
!= NULL
);
276 case EFI_IFR_TYPE_NUM_SIZE_8
:
277 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
280 case EFI_IFR_TYPE_NUM_SIZE_16
:
281 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
284 case EFI_IFR_TYPE_NUM_SIZE_32
:
285 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
288 case EFI_IFR_TYPE_NUM_SIZE_64
:
289 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
298 Check whether this value already in the array, if yes, return the index.
300 @param Array The data array.
301 @param Type Type of the data in this array.
302 @param Value The value to be find.
303 @param Index The index in the array which has same value with Value.
305 @retval TRUE Found the value in the array.
306 @retval FALSE Not found the value.
314 OUT UINTN
*Index OPTIONAL
321 ASSERT (Array
!= NULL
);
327 case EFI_IFR_TYPE_NUM_SIZE_8
:
328 ValueComp
= (UINT8
) Value
;
331 case EFI_IFR_TYPE_NUM_SIZE_16
:
332 ValueComp
= (UINT16
) Value
;
335 case EFI_IFR_TYPE_NUM_SIZE_32
:
336 ValueComp
= (UINT32
) Value
;
339 case EFI_IFR_TYPE_NUM_SIZE_64
:
340 ValueComp
= (UINT64
) Value
;
348 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
349 if (ValueComp
== TmpValue
) {
363 Print Question Value according to it's storage width and display attributes.
365 @param Question The Question to be printed.
366 @param FormattedNumber Buffer for output string.
367 @param BufferSize The FormattedNumber buffer size in bytes.
369 @retval EFI_SUCCESS Print success.
370 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
374 PrintFormattedNumber (
375 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
376 IN OUT CHAR16
*FormattedNumber
,
382 EFI_HII_VALUE
*QuestionValue
;
383 EFI_IFR_NUMERIC
*NumericOp
;
385 if (BufferSize
< (21 * sizeof (CHAR16
))) {
386 return EFI_BUFFER_TOO_SMALL
;
389 QuestionValue
= &Question
->CurrentValue
;
390 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
392 Value
= (INT64
) QuestionValue
->Value
.u64
;
393 switch (NumericOp
->Flags
& EFI_IFR_DISPLAY
) {
394 case EFI_IFR_DISPLAY_INT_DEC
:
395 switch (QuestionValue
->Type
) {
396 case EFI_IFR_NUMERIC_SIZE_1
:
397 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
400 case EFI_IFR_NUMERIC_SIZE_2
:
401 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
404 case EFI_IFR_NUMERIC_SIZE_4
:
405 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
408 case EFI_IFR_NUMERIC_SIZE_8
:
421 case EFI_IFR_DISPLAY_UINT_DEC
:
425 case EFI_IFR_DISPLAY_UINT_HEX
:
430 return EFI_UNSUPPORTED
;
434 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
441 Draw a pop up windows based on the dimension, number of lines and
444 @param RequestedWidth The width of the pop-up.
445 @param NumberOfLines The number of lines.
446 @param Marker The variable argument list for the list of string to be printed.
451 IN UINTN RequestedWidth
,
452 IN UINTN NumberOfLines
,
464 UINTN DimensionsWidth
;
465 UINTN DimensionsHeight
;
467 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
468 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
470 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
472 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
473 RequestedWidth
= DimensionsWidth
- 2;
477 // Subtract the PopUp width from total Columns, allow for one space extra on
478 // each end plus a border.
480 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
481 End
= Start
+ RequestedWidth
+ 1;
483 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gStatementDimensions
.TopRow
- 1;
484 Bottom
= Top
+ NumberOfLines
+ 2;
486 Character
= BOXDRAW_DOWN_RIGHT
;
487 PrintCharAt (Start
, Top
, Character
);
488 Character
= BOXDRAW_HORIZONTAL
;
489 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
490 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
493 Character
= BOXDRAW_DOWN_LEFT
;
494 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
495 Character
= BOXDRAW_VERTICAL
;
498 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
499 String
= VA_ARG (Marker
, CHAR16
*);
502 // This will clear the background of the line - we never know who might have been
503 // here before us. This differs from the next clear in that it used the non-reverse
504 // video for normal printing.
506 if (GetStringWidth (String
) / 2 > 1) {
507 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
511 // Passing in a space results in the assumption that this is where typing will occur
513 if (String
[0] == L
' ') {
514 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, GetPopupInverseColor ());
518 // Passing in a NULL results in a blank space
520 if (String
[0] == CHAR_NULL
) {
521 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
525 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gStatementDimensions
.LeftColumn
+ 1,
529 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
530 PrintCharAt (Start
, Index
+ 1, Character
);
531 PrintCharAt (End
- 1, Index
+ 1, Character
);
534 Character
= BOXDRAW_UP_RIGHT
;
535 PrintCharAt (Start
, Bottom
- 1, Character
);
536 Character
= BOXDRAW_HORIZONTAL
;
537 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
538 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
541 Character
= BOXDRAW_UP_LEFT
;
542 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
546 Draw a pop up windows based on the dimension, number of lines and
549 @param RequestedWidth The width of the pop-up.
550 @param NumberOfLines The number of lines.
551 @param ... A series of text strings that displayed in the pop-up.
556 CreateMultiStringPopUp (
557 IN UINTN RequestedWidth
,
558 IN UINTN NumberOfLines
,
564 VA_START (Marker
, NumberOfLines
);
566 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
574 @param Event The Event need to be process
575 @param Context The context of the event.
588 Process for the refresh interval statement.
590 @param Event The Event need to be process
591 @param Context The context of the event.
596 RefreshTimeOutProcess (
601 WARNING_IF_CONTEXT
*EventInfo
;
602 CHAR16 TimeOutString
[MAX_TIME_OUT_LEN
];
604 EventInfo
= (WARNING_IF_CONTEXT
*) Context
;
606 if (*(EventInfo
->TimeOut
) == 0) {
607 gBS
->CloseEvent (Event
);
609 gBS
->SignalEvent (EventInfo
->SyncEvent
);
613 UnicodeSPrint(TimeOutString
, MAX_TIME_OUT_LEN
, L
"%d", *(EventInfo
->TimeOut
));
615 CreateDialog (NULL
, gEmptyString
, EventInfo
->ErrorInfo
, gPressEnter
, gEmptyString
, TimeOutString
, NULL
);
617 *(EventInfo
->TimeOut
) -= 1;
621 Show the warning message.
623 @param RetInfo The input warning string and timeout info.
628 IN STATEMENT_ERROR_INFO
*RetInfo
632 EFI_EVENT WaitList
[2];
633 EFI_EVENT RefreshIntervalEvent
;
634 EFI_EVENT TimeOutEvent
;
638 WARNING_IF_CONTEXT EventContext
;
642 RefreshIntervalEvent
= NULL
;
644 ASSERT (RetInfo
->StringId
!= 0);
645 ErrorInfo
= GetToken (RetInfo
->StringId
, gFormData
->HiiHandle
);
646 TimeOut
= RetInfo
->TimeOut
;
647 if (RetInfo
->TimeOut
== 0) {
649 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
650 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
652 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
653 ASSERT_EFI_ERROR (Status
);
655 EventContext
.SyncEvent
= TimeOutEvent
;
656 EventContext
.TimeOut
= &TimeOut
;
657 EventContext
.ErrorInfo
= ErrorInfo
;
659 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
660 ASSERT_EFI_ERROR (Status
);
663 // Show the dialog first to avoid long time not reaction.
665 gBS
->SignalEvent (RefreshIntervalEvent
);
667 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
668 ASSERT_EFI_ERROR (Status
);
671 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
672 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
676 if (Status
!= EFI_NOT_READY
) {
680 WaitList
[0] = TimeOutEvent
;
681 WaitList
[1] = gST
->ConIn
->WaitForKey
;
683 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
684 ASSERT_EFI_ERROR (Status
);
688 // Timeout occur, close the hoot time out event.
695 gBS
->CloseEvent (TimeOutEvent
);
696 gBS
->CloseEvent (RefreshIntervalEvent
);
698 FreePool (ErrorInfo
);
702 Process validate for one question.
704 @param Question The question need to be validate.
706 @retval EFI_SUCCESS Question Option process success.
707 @retval EFI_INVALID_PARAMETER Question Option process fail.
712 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
718 STATEMENT_ERROR_INFO RetInfo
;
721 if (Question
->ValidateQuestion
== NULL
) {
725 Status
= EFI_SUCCESS
;
726 RetVal
= Question
->ValidateQuestion(gFormData
, Question
, &gUserInput
->InputValue
, &RetInfo
);
729 case INCOSISTENT_IF_TRUE
:
731 // Condition meet, show up error message
733 ASSERT (RetInfo
.StringId
!= 0);
734 ErrorInfo
= GetToken (RetInfo
.StringId
, gFormData
->HiiHandle
);
736 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
737 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
738 FreePool (ErrorInfo
);
740 Status
= EFI_INVALID_PARAMETER
;
743 case WARNING_IF_TRUE
:
745 // Condition meet, show up warning message
747 WarningIfCheck (&RetInfo
);
758 Display error message for invalid password.
769 // Invalid password, prompt error message
772 CreateDialog (&Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
, NULL
);
773 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
777 Process password op code.
779 @param MenuOption The menu for current password op code.
781 @retval EFI_SUCCESS Question Option process success.
782 @retval Other Question Option process fail.
787 IN UI_MENU_OPTION
*MenuOption
794 EFI_IFR_PASSWORD
*PasswordInfo
;
795 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
798 Question
= MenuOption
->ThisTag
;
799 PasswordInfo
= (EFI_IFR_PASSWORD
*) Question
->OpCode
;
800 Maximum
= PasswordInfo
->MaxSize
;
801 Status
= EFI_SUCCESS
;
803 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
807 // Use a NULL password to test whether old password is required
810 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
811 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
813 // Password can't be set now.
815 FreePool (StringPtr
);
819 if (EFI_ERROR (Status
)) {
821 // Old password exist, ask user for the old password
823 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
824 if (EFI_ERROR (Status
)) {
825 FreePool (StringPtr
);
830 // Check user input old password
832 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
833 if (EFI_ERROR (Status
)) {
834 if (Status
== EFI_NOT_READY
) {
836 // Typed in old password incorrect
840 Status
= EFI_SUCCESS
;
843 FreePool (StringPtr
);
849 // Ask for new password
851 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
852 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
853 if (EFI_ERROR (Status
)) {
855 // Reset state machine for password
857 Question
->PasswordCheck (gFormData
, Question
, NULL
);
858 FreePool (StringPtr
);
863 // Confirm new password
865 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
867 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
868 if (EFI_ERROR (Status
)) {
870 // Reset state machine for password
872 Question
->PasswordCheck (gFormData
, Question
, NULL
);
873 FreePool (StringPtr
);
874 FreePool (TempString
);
879 // Compare two typed-in new passwords
881 if (StrCmp (StringPtr
, TempString
) == 0) {
882 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
883 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
884 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
885 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
886 FreePool (StringPtr
);
888 Status
= ValidateQuestion (Question
);
890 if (EFI_ERROR (Status
)) {
892 // Reset state machine for password
894 Question
->PasswordCheck (gFormData
, Question
, NULL
);
900 // Reset state machine for password
902 Question
->PasswordCheck (gFormData
, Question
, NULL
);
905 // Two password mismatch, prompt error message
908 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
909 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
911 Status
= EFI_INVALID_PARAMETER
;
914 FreePool (TempString
);
915 FreePool (StringPtr
);
921 Process a Question's Option (whether selected or un-selected).
923 @param MenuOption The MenuOption for this Question.
924 @param Selected TRUE: if Question is selected.
925 @param OptionString Pointer of the Option String to be displayed.
926 @param SkipErrorValue Whether need to return when value without option for it.
928 @retval EFI_SUCCESS Question Option process success.
929 @retval Other Question Option process fail.
934 IN UI_MENU_OPTION
*MenuOption
,
936 OUT CHAR16
**OptionString
,
937 IN BOOLEAN SkipErrorValue
943 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
944 CHAR16 FormattedNumber
[21];
949 DISPLAY_QUESTION_OPTION
*OneOfOption
;
951 EFI_HII_VALUE HiiValue
;
952 EFI_HII_VALUE
*QuestionValue
;
953 DISPLAY_QUESTION_OPTION
*Option
;
957 EFI_STRING_ID StringId
;
958 EFI_IFR_ORDERED_LIST
*OrderList
;
959 BOOLEAN ValueInvalid
;
961 Status
= EFI_SUCCESS
;
964 Character
[1] = L
'\0';
965 *OptionString
= NULL
;
967 ValueInvalid
= FALSE
;
969 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
970 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
972 Question
= MenuOption
->ThisTag
;
973 QuestionValue
= &Question
->CurrentValue
;
975 switch (Question
->OpCode
->OpCode
) {
976 case EFI_IFR_ORDERED_LIST_OP
:
979 // Check whether there are Options of this OrderedList
981 if (IsListEmpty (&Question
->OptionListHead
)) {
985 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
987 Link
= GetFirstNode (&Question
->OptionListHead
);
988 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
990 ValueType
= OneOfOption
->OptionOpCode
->Type
;
991 ValueArray
= Question
->CurrentValue
.Buffer
;
997 Status
= GetSelectionInputPopUp (MenuOption
);
1000 // We now know how many strings we will have, so we can allocate the
1001 // space required for the array or strings.
1003 *OptionString
= AllocateZeroPool (OrderList
->MaxContainers
* BufferSize
);
1004 ASSERT (*OptionString
);
1006 HiiValue
.Type
= ValueType
;
1007 HiiValue
.Value
.u64
= 0;
1008 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1009 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1010 if (HiiValue
.Value
.u64
== 0) {
1012 // Values for the options in ordered lists should never be a 0
1017 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1018 if (OneOfOption
== NULL
) {
1019 if (SkipErrorValue
) {
1021 // Just try to get the option string, skip the value which not has option.
1027 // Show error message
1030 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1031 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1034 // The initial value of the orderedlist is invalid, force to be valid value
1035 // Exit current DisplayForm with new value.
1037 gUserInput
->SelectedStatement
= Question
;
1039 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1040 ASSERT (ValueArray
!= NULL
);
1041 gUserInput
->InputValue
.Buffer
= ValueArray
;
1042 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1043 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1045 Link
= GetFirstNode (&Question
->OptionListHead
);
1047 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
1048 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1049 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1050 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
1053 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
1055 FreePool (*OptionString
);
1056 *OptionString
= NULL
;
1057 return EFI_NOT_FOUND
;
1060 Character
[0] = LEFT_ONEOF_DELIMITER
;
1061 NewStrCat (OptionString
[0], Character
);
1062 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1063 ASSERT (StringPtr
!= NULL
);
1064 NewStrCat (OptionString
[0], StringPtr
);
1065 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1066 NewStrCat (OptionString
[0], Character
);
1067 Character
[0] = CHAR_CARRIAGE_RETURN
;
1068 NewStrCat (OptionString
[0], Character
);
1069 FreePool (StringPtr
);
1073 // If valid option more than the max container, skip these options.
1075 if (Index
>= OrderList
->MaxContainers
) {
1080 // Search the other options, try to find the one not in the container.
1082 Link
= GetFirstNode (&Question
->OptionListHead
);
1083 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1084 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1085 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1087 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
1091 if (SkipErrorValue
) {
1093 // Not report error, just get the correct option string info.
1095 Character
[0] = LEFT_ONEOF_DELIMITER
;
1096 NewStrCat (OptionString
[0], Character
);
1097 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1098 ASSERT (StringPtr
!= NULL
);
1099 NewStrCat (OptionString
[0], StringPtr
);
1100 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1101 NewStrCat (OptionString
[0], Character
);
1102 Character
[0] = CHAR_CARRIAGE_RETURN
;
1103 NewStrCat (OptionString
[0], Character
);
1104 FreePool (StringPtr
);
1109 if (!ValueInvalid
) {
1110 ValueInvalid
= TRUE
;
1112 // Show error message
1115 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1116 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1119 // The initial value of the orderedlist is invalid, force to be valid value
1120 // Exit current DisplayForm with new value.
1122 gUserInput
->SelectedStatement
= Question
;
1124 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
1125 ASSERT (ValueArray
!= NULL
);
1126 gUserInput
->InputValue
.Buffer
= ValueArray
;
1127 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1128 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1131 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
1135 FreePool (*OptionString
);
1136 *OptionString
= NULL
;
1137 return EFI_NOT_FOUND
;
1142 case EFI_IFR_ONE_OF_OP
:
1144 // Check whether there are Options of this OneOf
1146 if (IsListEmpty (&Question
->OptionListHead
)) {
1153 Status
= GetSelectionInputPopUp (MenuOption
);
1155 *OptionString
= AllocateZeroPool (BufferSize
);
1156 ASSERT (*OptionString
);
1158 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1159 if (OneOfOption
== NULL
) {
1160 if (SkipErrorValue
) {
1162 // Not report error, just get the correct option string info.
1164 Link
= GetFirstNode (&Question
->OptionListHead
);
1165 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1168 // Show error message
1171 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1172 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1175 // Force the Question value to be valid
1176 // Exit current DisplayForm with new value.
1178 Link
= GetFirstNode (&Question
->OptionListHead
);
1179 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1181 CopyMem (&gUserInput
->InputValue
.Value
, &Option
->OptionOpCode
->Value
, sizeof (EFI_IFR_TYPE_VALUE
));
1182 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1183 gUserInput
->SelectedStatement
= Question
;
1185 FreePool (*OptionString
);
1186 *OptionString
= NULL
;
1187 return EFI_NOT_FOUND
;
1191 Character
[0] = LEFT_ONEOF_DELIMITER
;
1192 NewStrCat (OptionString
[0], Character
);
1193 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1194 ASSERT (StringPtr
!= NULL
);
1195 NewStrCat (OptionString
[0], StringPtr
);
1196 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1197 NewStrCat (OptionString
[0], Character
);
1199 FreePool (StringPtr
);
1203 case EFI_IFR_CHECKBOX_OP
:
1206 // Since this is a BOOLEAN operation, flip it upon selection
1208 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1209 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
1212 // Perform inconsistent check
1214 return ValidateQuestion (Question
);
1216 *OptionString
= AllocateZeroPool (BufferSize
);
1217 ASSERT (*OptionString
);
1219 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1221 if (QuestionValue
->Value
.b
) {
1222 *(OptionString
[0] + 1) = CHECK_ON
;
1224 *(OptionString
[0] + 1) = CHECK_OFF
;
1226 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1230 case EFI_IFR_NUMERIC_OP
:
1235 Status
= GetNumericInput (MenuOption
);
1237 *OptionString
= AllocateZeroPool (BufferSize
);
1238 ASSERT (*OptionString
);
1240 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1245 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1246 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
1247 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1249 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1253 case EFI_IFR_DATE_OP
:
1256 // This is similar to numerics
1258 Status
= GetNumericInput (MenuOption
);
1260 *OptionString
= AllocateZeroPool (BufferSize
);
1261 ASSERT (*OptionString
);
1263 switch (MenuOption
->Sequence
) {
1265 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1266 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1267 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1271 SetUnicodeMem (OptionString
[0], 4, L
' ');
1272 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1273 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1277 SetUnicodeMem (OptionString
[0], 7, L
' ');
1278 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1279 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1285 case EFI_IFR_TIME_OP
:
1288 // This is similar to numerics
1290 Status
= GetNumericInput (MenuOption
);
1292 *OptionString
= AllocateZeroPool (BufferSize
);
1293 ASSERT (*OptionString
);
1295 switch (MenuOption
->Sequence
) {
1297 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1298 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1299 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1303 SetUnicodeMem (OptionString
[0], 4, L
' ');
1304 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1305 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1309 SetUnicodeMem (OptionString
[0], 7, L
' ');
1310 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1311 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1317 case EFI_IFR_STRING_OP
:
1319 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1321 CopyMem(StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1323 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1324 if (EFI_ERROR (Status
)) {
1325 FreePool (StringPtr
);
1329 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1330 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1331 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1332 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1333 FreePool (StringPtr
);
1334 return ValidateQuestion (Question
);
1336 *OptionString
= AllocateZeroPool (BufferSize
);
1337 ASSERT (*OptionString
);
1339 if (((CHAR16
*) Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1340 *(OptionString
[0]) = '_';
1342 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1343 BufferSize
= Question
->CurrentValue
.BufferLen
;
1345 CopyMem (OptionString
[0], (CHAR16
*) Question
->CurrentValue
.Buffer
, BufferSize
);
1350 case EFI_IFR_PASSWORD_OP
:
1352 Status
= PasswordProcess (MenuOption
);
1365 Process the help string: Split StringPtr to several lines of strings stored in
1366 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1368 @param StringPtr The entire help string.
1369 @param FormattedString The oupput formatted string.
1370 @param EachLineWidth The max string length of each line in the formatted string.
1371 @param RowCount TRUE: if Question is selected.
1376 IN CHAR16
*StringPtr
,
1377 OUT CHAR16
**FormattedString
,
1378 OUT UINT16
*EachLineWidth
,
1383 CHAR16
*OutputString
;
1388 UINT16 MaxStringLen
;
1399 // Set default help string width.
1401 LineWidth
= (UINT16
) (gHelpBlockWidth
- 1);
1404 // Get row number of the String.
1406 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1407 if (StringLen
> MaxStringLen
) {
1408 MaxStringLen
= StringLen
;
1412 FreePool (OutputString
);
1414 *EachLineWidth
= MaxStringLen
;
1416 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1417 ASSERT (*FormattedString
!= NULL
);
1420 // Generate formatted help string array.
1424 while((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1425 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1427 FreePool (OutputString
);