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 Get UINT64 type value.
60 @param Value Input Hii value.
62 @retval UINT64 Return the UINT64 type value.
67 IN EFI_HII_VALUE
*Value
74 switch (Value
->Type
) {
75 case EFI_IFR_TYPE_NUM_SIZE_8
:
76 RetVal
= Value
->Value
.u8
;
79 case EFI_IFR_TYPE_NUM_SIZE_16
:
80 RetVal
= Value
->Value
.u16
;
83 case EFI_IFR_TYPE_NUM_SIZE_32
:
84 RetVal
= Value
->Value
.u32
;
87 case EFI_IFR_TYPE_BOOLEAN
:
88 RetVal
= Value
->Value
.b
;
91 case EFI_IFR_TYPE_DATE
:
92 RetVal
= *(UINT64
*) &Value
->Value
.date
;
95 case EFI_IFR_TYPE_TIME
:
96 RetVal
= (*(UINT64
*) &Value
->Value
.time
) & 0xffffff;
100 RetVal
= Value
->Value
.u64
;
108 Compare two Hii value.
110 @param Value1 Expression value to compare on left-hand.
111 @param Value2 Expression value to compare on right-hand.
112 @param Result Return value after compare.
113 retval 0 Two operators equal.
114 return Positive value if Value1 is greater than Value2.
115 retval Negative value if Value1 is less than Value2.
116 @param HiiHandle Only required for string compare.
118 @retval other Could not perform compare on two values.
119 @retval EFI_SUCCESS Compare the value success.
124 IN EFI_HII_VALUE
*Value1
,
125 IN EFI_HII_VALUE
*Value2
,
127 IN EFI_HII_HANDLE HiiHandle OPTIONAL
135 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
136 if (Value1
->Type
!= EFI_IFR_TYPE_BUFFER
&& Value2
->Type
!= EFI_IFR_TYPE_BUFFER
) {
137 return EFI_UNSUPPORTED
;
141 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
142 if (Value1
->Type
!= Value2
->Type
) {
144 // Both Operator should be type of String
146 return EFI_UNSUPPORTED
;
149 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
151 // StringId 0 is reserved
153 return EFI_INVALID_PARAMETER
;
156 if (Value1
->Value
.string
== Value2
->Value
.string
) {
161 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
166 return EFI_NOT_FOUND
;
169 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
172 return EFI_NOT_FOUND
;
175 *Result
= StrCmp (Str1
, Str2
);
183 if (Value1
->Type
== EFI_IFR_TYPE_BUFFER
|| Value2
->Type
== EFI_IFR_TYPE_BUFFER
) {
184 if (Value1
->Type
!= Value2
->Type
) {
186 // Both Operator should be type of Buffer.
188 return EFI_UNSUPPORTED
;
190 Len
= Value1
->BufferLen
> Value2
->BufferLen
? Value2
->BufferLen
: Value1
->BufferLen
;
191 *Result
= CompareMem (Value1
->Buffer
, Value2
->Buffer
, Len
);
192 if ((*Result
== 0) && (Value1
->BufferLen
!= Value2
->BufferLen
))
195 // In this case, means base on samll number buffer, the data is same
196 // So which value has more data, which value is bigger.
198 *Result
= Value1
->BufferLen
> Value2
->BufferLen
? 1 : -1;
204 // Take remain types(integer, boolean, date/time) as integer
206 Temp64
= HiiValueToUINT64(Value1
) - HiiValueToUINT64(Value2
);
209 } else if (Temp64
< 0) {
219 Search an Option of a Question by its value.
221 @param Question The Question
222 @param OptionValue Value for Option to be searched.
224 @retval Pointer Pointer to the found Option.
225 @retval NULL Option not found.
228 DISPLAY_QUESTION_OPTION
*
230 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
231 IN EFI_HII_VALUE
*OptionValue
235 DISPLAY_QUESTION_OPTION
*Option
;
239 Link
= GetFirstNode (&Question
->OptionListHead
);
240 while (!IsNull (&Question
->OptionListHead
, Link
)) {
241 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
243 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
244 Value
.Type
= Option
->OptionOpCode
->Type
;
245 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
247 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
251 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
259 Return data element in an Array by its Index.
261 @param Array The data array.
262 @param Type Type of the data in this array.
263 @param Index Zero based index for data in this array.
265 @retval Value The data to be returned
277 ASSERT (Array
!= NULL
);
281 case EFI_IFR_TYPE_NUM_SIZE_8
:
282 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
285 case EFI_IFR_TYPE_NUM_SIZE_16
:
286 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
289 case EFI_IFR_TYPE_NUM_SIZE_32
:
290 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
293 case EFI_IFR_TYPE_NUM_SIZE_64
:
294 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
306 Set value of a data element in an Array by its Index.
308 @param Array The data array.
309 @param Type Type of the data in this array.
310 @param Index Zero based index for data in this array.
311 @param Value The value to be set.
323 ASSERT (Array
!= NULL
);
326 case EFI_IFR_TYPE_NUM_SIZE_8
:
327 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
330 case EFI_IFR_TYPE_NUM_SIZE_16
:
331 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
334 case EFI_IFR_TYPE_NUM_SIZE_32
:
335 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
338 case EFI_IFR_TYPE_NUM_SIZE_64
:
339 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
348 Check whether this value already in the array, if yes, return the index.
350 @param Array The data array.
351 @param Type Type of the data in this array.
352 @param Value The value to be find.
353 @param Index The index in the array which has same value with Value.
355 @retval TRUE Found the value in the array.
356 @retval FALSE Not found the value.
364 OUT UINTN
*Index OPTIONAL
371 ASSERT (Array
!= NULL
);
377 case EFI_IFR_TYPE_NUM_SIZE_8
:
378 ValueComp
= (UINT8
) Value
;
381 case EFI_IFR_TYPE_NUM_SIZE_16
:
382 ValueComp
= (UINT16
) Value
;
385 case EFI_IFR_TYPE_NUM_SIZE_32
:
386 ValueComp
= (UINT32
) Value
;
389 case EFI_IFR_TYPE_NUM_SIZE_64
:
390 ValueComp
= (UINT64
) Value
;
398 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
399 if (ValueComp
== TmpValue
) {
413 Print Question Value according to it's storage width and display attributes.
415 @param Question The Question to be printed.
416 @param FormattedNumber Buffer for output string.
417 @param BufferSize The FormattedNumber buffer size in bytes.
419 @retval EFI_SUCCESS Print success.
420 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
424 PrintFormattedNumber (
425 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
426 IN OUT CHAR16
*FormattedNumber
,
432 EFI_HII_VALUE
*QuestionValue
;
433 EFI_IFR_NUMERIC
*NumericOp
;
435 if (BufferSize
< (21 * sizeof (CHAR16
))) {
436 return EFI_BUFFER_TOO_SMALL
;
439 QuestionValue
= &Question
->CurrentValue
;
440 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
442 Value
= (INT64
) QuestionValue
->Value
.u64
;
443 switch (NumericOp
->Flags
& EFI_IFR_DISPLAY
) {
444 case EFI_IFR_DISPLAY_INT_DEC
:
445 switch (QuestionValue
->Type
) {
446 case EFI_IFR_NUMERIC_SIZE_1
:
447 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
450 case EFI_IFR_NUMERIC_SIZE_2
:
451 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
454 case EFI_IFR_NUMERIC_SIZE_4
:
455 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
458 case EFI_IFR_NUMERIC_SIZE_8
:
471 case EFI_IFR_DISPLAY_UINT_DEC
:
475 case EFI_IFR_DISPLAY_UINT_HEX
:
480 return EFI_UNSUPPORTED
;
484 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
491 Draw a pop up windows based on the dimension, number of lines and
494 @param RequestedWidth The width of the pop-up.
495 @param NumberOfLines The number of lines.
496 @param Marker The variable argument list for the list of string to be printed.
501 IN UINTN RequestedWidth
,
502 IN UINTN NumberOfLines
,
514 UINTN DimensionsWidth
;
515 UINTN DimensionsHeight
;
517 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
518 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
520 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
522 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
523 RequestedWidth
= DimensionsWidth
- 2;
527 // Subtract the PopUp width from total Columns, allow for one space extra on
528 // each end plus a border.
530 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
531 End
= Start
+ RequestedWidth
+ 1;
533 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gStatementDimensions
.TopRow
- 1;
534 Bottom
= Top
+ NumberOfLines
+ 2;
536 Character
= BOXDRAW_DOWN_RIGHT
;
537 PrintCharAt (Start
, Top
, Character
);
538 Character
= BOXDRAW_HORIZONTAL
;
539 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
540 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
543 Character
= BOXDRAW_DOWN_LEFT
;
544 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
545 Character
= BOXDRAW_VERTICAL
;
548 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
549 String
= VA_ARG (Marker
, CHAR16
*);
552 // This will clear the background of the line - we never know who might have been
553 // here before us. This differs from the next clear in that it used the non-reverse
554 // video for normal printing.
556 if (GetStringWidth (String
) / 2 > 1) {
557 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
561 // Passing in a space results in the assumption that this is where typing will occur
563 if (String
[0] == L
' ') {
564 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, GetPopupInverseColor ());
568 // Passing in a NULL results in a blank space
570 if (String
[0] == CHAR_NULL
) {
571 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
575 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gStatementDimensions
.LeftColumn
+ 1,
579 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
580 PrintCharAt (Start
, Index
+ 1, Character
);
581 PrintCharAt (End
- 1, Index
+ 1, Character
);
584 Character
= BOXDRAW_UP_RIGHT
;
585 PrintCharAt (Start
, Bottom
- 1, Character
);
586 Character
= BOXDRAW_HORIZONTAL
;
587 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
588 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
591 Character
= BOXDRAW_UP_LEFT
;
592 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
596 Draw a pop up windows based on the dimension, number of lines and
599 @param RequestedWidth The width of the pop-up.
600 @param NumberOfLines The number of lines.
601 @param ... A series of text strings that displayed in the pop-up.
606 CreateMultiStringPopUp (
607 IN UINTN RequestedWidth
,
608 IN UINTN NumberOfLines
,
614 VA_START (Marker
, NumberOfLines
);
616 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
624 @param Event The Event need to be process
625 @param Context The context of the event.
638 Process for the refresh interval statement.
640 @param Event The Event need to be process
641 @param Context The context of the event.
646 RefreshTimeOutProcess (
651 WARNING_IF_CONTEXT
*EventInfo
;
652 CHAR16 TimeOutString
[MAX_TIME_OUT_LEN
];
654 EventInfo
= (WARNING_IF_CONTEXT
*) Context
;
656 if (*(EventInfo
->TimeOut
) == 0) {
657 gBS
->CloseEvent (Event
);
659 gBS
->SignalEvent (EventInfo
->SyncEvent
);
663 UnicodeSPrint(TimeOutString
, MAX_TIME_OUT_LEN
, L
"%d", *(EventInfo
->TimeOut
));
665 CreateDialog (NULL
, gEmptyString
, EventInfo
->ErrorInfo
, gPressEnter
, gEmptyString
, TimeOutString
, NULL
);
667 *(EventInfo
->TimeOut
) -= 1;
671 Show the warning message.
673 @param RetInfo The input warning string and timeout info.
678 IN STATEMENT_ERROR_INFO
*RetInfo
682 EFI_EVENT WaitList
[2];
683 EFI_EVENT RefreshIntervalEvent
;
684 EFI_EVENT TimeOutEvent
;
688 WARNING_IF_CONTEXT EventContext
;
692 RefreshIntervalEvent
= NULL
;
694 ASSERT (RetInfo
->StringId
!= 0);
695 ErrorInfo
= GetToken (RetInfo
->StringId
, gFormData
->HiiHandle
);
696 TimeOut
= RetInfo
->TimeOut
;
697 if (RetInfo
->TimeOut
== 0) {
699 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
700 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
702 Status
= gBS
->CreateEvent (EVT_NOTIFY_WAIT
, TPL_CALLBACK
, EmptyEventProcess
, NULL
, &TimeOutEvent
);
703 ASSERT_EFI_ERROR (Status
);
705 EventContext
.SyncEvent
= TimeOutEvent
;
706 EventContext
.TimeOut
= &TimeOut
;
707 EventContext
.ErrorInfo
= ErrorInfo
;
709 Status
= gBS
->CreateEvent (EVT_TIMER
| EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, RefreshTimeOutProcess
, &EventContext
, &RefreshIntervalEvent
);
710 ASSERT_EFI_ERROR (Status
);
713 // Show the dialog first to avoid long time not reaction.
715 gBS
->SignalEvent (RefreshIntervalEvent
);
717 Status
= gBS
->SetTimer (RefreshIntervalEvent
, TimerPeriodic
, ONE_SECOND
);
718 ASSERT_EFI_ERROR (Status
);
721 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
722 if (!EFI_ERROR (Status
) && Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
726 if (Status
!= EFI_NOT_READY
) {
730 WaitList
[0] = TimeOutEvent
;
731 WaitList
[1] = gST
->ConIn
->WaitForKey
;
733 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
734 ASSERT_EFI_ERROR (Status
);
738 // Timeout occur, close the hoot time out event.
745 gBS
->CloseEvent (TimeOutEvent
);
746 gBS
->CloseEvent (RefreshIntervalEvent
);
748 FreePool (ErrorInfo
);
752 Process validate for one question.
754 @param Question The question need to be validate.
756 @retval EFI_SUCCESS Question Option process success.
757 @retval EFI_INVALID_PARAMETER Question Option process fail.
762 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
768 STATEMENT_ERROR_INFO RetInfo
;
771 if (Question
->ValidateQuestion
== NULL
) {
775 Status
= EFI_SUCCESS
;
776 RetVal
= Question
->ValidateQuestion(gFormData
, Question
, &gUserInput
->InputValue
, &RetInfo
);
779 case INCOSISTENT_IF_TRUE
:
781 // Condition meet, show up error message
783 ASSERT (RetInfo
.StringId
!= 0);
784 ErrorInfo
= GetToken (RetInfo
.StringId
, gFormData
->HiiHandle
);
786 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
787 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
788 FreePool (ErrorInfo
);
790 Status
= EFI_INVALID_PARAMETER
;
793 case WARNING_IF_TRUE
:
795 // Condition meet, show up warning message
797 WarningIfCheck (&RetInfo
);
808 Display error message for invalid password.
819 // Invalid password, prompt error message
822 CreateDialog (&Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
, NULL
);
823 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
827 Process password op code.
829 @param MenuOption The menu for current password op code.
831 @retval EFI_SUCCESS Question Option process success.
832 @retval Other Question Option process fail.
837 IN UI_MENU_OPTION
*MenuOption
844 EFI_IFR_PASSWORD
*PasswordInfo
;
845 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
848 Question
= MenuOption
->ThisTag
;
849 PasswordInfo
= (EFI_IFR_PASSWORD
*) Question
->OpCode
;
850 Maximum
= PasswordInfo
->MaxSize
;
851 Status
= EFI_SUCCESS
;
853 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
857 // Use a NULL password to test whether old password is required
860 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
861 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
863 // Password can't be set now.
865 FreePool (StringPtr
);
869 if (EFI_ERROR (Status
)) {
871 // Old password exist, ask user for the old password
873 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
874 if (EFI_ERROR (Status
)) {
875 FreePool (StringPtr
);
880 // Check user input old password
882 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
883 if (EFI_ERROR (Status
)) {
884 if (Status
== EFI_NOT_READY
) {
886 // Typed in old password incorrect
890 Status
= EFI_SUCCESS
;
893 FreePool (StringPtr
);
899 // Ask for new password
901 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
902 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
903 if (EFI_ERROR (Status
)) {
905 // Reset state machine for password
907 Question
->PasswordCheck (gFormData
, Question
, NULL
);
908 FreePool (StringPtr
);
913 // Confirm new password
915 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
917 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
918 if (EFI_ERROR (Status
)) {
920 // Reset state machine for password
922 Question
->PasswordCheck (gFormData
, Question
, NULL
);
923 FreePool (StringPtr
);
924 FreePool (TempString
);
929 // Compare two typed-in new passwords
931 if (StrCmp (StringPtr
, TempString
) == 0) {
932 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
933 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
934 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
935 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
936 FreePool (StringPtr
);
938 Status
= ValidateQuestion (Question
);
940 if (EFI_ERROR (Status
)) {
942 // Reset state machine for password
944 Question
->PasswordCheck (gFormData
, Question
, NULL
);
950 // Reset state machine for password
952 Question
->PasswordCheck (gFormData
, Question
, NULL
);
955 // Two password mismatch, prompt error message
958 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
959 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
961 Status
= EFI_INVALID_PARAMETER
;
964 FreePool (TempString
);
965 FreePool (StringPtr
);
971 Process a Question's Option (whether selected or un-selected).
973 @param MenuOption The MenuOption for this Question.
974 @param Selected TRUE: if Question is selected.
975 @param OptionString Pointer of the Option String to be displayed.
976 @param SkipErrorValue Whether need to return when value without option for it.
978 @retval EFI_SUCCESS Question Option process success.
979 @retval Other Question Option process fail.
984 IN UI_MENU_OPTION
*MenuOption
,
986 OUT CHAR16
**OptionString
,
987 IN BOOLEAN SkipErrorValue
993 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
994 CHAR16 FormattedNumber
[21];
999 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1001 EFI_HII_VALUE HiiValue
;
1002 EFI_HII_VALUE
*QuestionValue
;
1003 DISPLAY_QUESTION_OPTION
*Option
;
1007 EFI_STRING_ID StringId
;
1008 EFI_IFR_ORDERED_LIST
*OrderList
;
1009 BOOLEAN ValueInvalid
;
1011 Status
= EFI_SUCCESS
;
1014 Character
[1] = L
'\0';
1015 *OptionString
= NULL
;
1017 ValueInvalid
= FALSE
;
1019 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
1020 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
1022 Question
= MenuOption
->ThisTag
;
1023 QuestionValue
= &Question
->CurrentValue
;
1025 switch (Question
->OpCode
->OpCode
) {
1026 case EFI_IFR_ORDERED_LIST_OP
:
1029 // Check whether there are Options of this OrderedList
1031 if (IsListEmpty (&Question
->OptionListHead
)) {
1035 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1037 Link
= GetFirstNode (&Question
->OptionListHead
);
1038 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1040 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1041 ValueArray
= Question
->CurrentValue
.Buffer
;
1047 Status
= GetSelectionInputPopUp (MenuOption
);
1050 // We now know how many strings we will have, so we can allocate the
1051 // space required for the array or strings.
1053 *OptionString
= AllocateZeroPool (OrderList
->MaxContainers
* BufferSize
);
1054 ASSERT (*OptionString
);
1056 HiiValue
.Type
= ValueType
;
1057 HiiValue
.Value
.u64
= 0;
1058 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1059 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1060 if (HiiValue
.Value
.u64
== 0) {
1062 // Values for the options in ordered lists should never be a 0
1067 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1068 if (OneOfOption
== NULL
) {
1069 if (SkipErrorValue
) {
1071 // Just try to get the option string, skip the value which not has option.
1077 // Show error message
1080 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1081 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1084 // The initial value of the orderedlist is invalid, force to be valid value
1085 // Exit current DisplayForm with new value.
1087 gUserInput
->SelectedStatement
= Question
;
1089 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1090 ASSERT (ValueArray
!= NULL
);
1091 gUserInput
->InputValue
.Buffer
= ValueArray
;
1092 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1093 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1095 Link
= GetFirstNode (&Question
->OptionListHead
);
1097 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
1098 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1099 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1100 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
1103 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
1105 FreePool (*OptionString
);
1106 *OptionString
= NULL
;
1107 return EFI_NOT_FOUND
;
1110 Character
[0] = LEFT_ONEOF_DELIMITER
;
1111 NewStrCat (OptionString
[0], Character
);
1112 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1113 ASSERT (StringPtr
!= NULL
);
1114 NewStrCat (OptionString
[0], StringPtr
);
1115 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1116 NewStrCat (OptionString
[0], Character
);
1117 Character
[0] = CHAR_CARRIAGE_RETURN
;
1118 NewStrCat (OptionString
[0], Character
);
1119 FreePool (StringPtr
);
1123 // If valid option more than the max container, skip these options.
1125 if (Index
>= OrderList
->MaxContainers
) {
1130 // Search the other options, try to find the one not in the container.
1132 Link
= GetFirstNode (&Question
->OptionListHead
);
1133 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1134 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1135 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1137 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
1141 if (SkipErrorValue
) {
1143 // Not report error, just get the correct option string info.
1145 Character
[0] = LEFT_ONEOF_DELIMITER
;
1146 NewStrCat (OptionString
[0], Character
);
1147 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1148 ASSERT (StringPtr
!= NULL
);
1149 NewStrCat (OptionString
[0], StringPtr
);
1150 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1151 NewStrCat (OptionString
[0], Character
);
1152 Character
[0] = CHAR_CARRIAGE_RETURN
;
1153 NewStrCat (OptionString
[0], Character
);
1154 FreePool (StringPtr
);
1159 if (!ValueInvalid
) {
1160 ValueInvalid
= TRUE
;
1162 // Show error message
1165 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1166 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1169 // The initial value of the orderedlist is invalid, force to be valid value
1170 // Exit current DisplayForm with new value.
1172 gUserInput
->SelectedStatement
= Question
;
1174 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
1175 ASSERT (ValueArray
!= NULL
);
1176 gUserInput
->InputValue
.Buffer
= ValueArray
;
1177 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1178 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1181 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
1185 FreePool (*OptionString
);
1186 *OptionString
= NULL
;
1187 return EFI_NOT_FOUND
;
1192 case EFI_IFR_ONE_OF_OP
:
1194 // Check whether there are Options of this OneOf
1196 if (IsListEmpty (&Question
->OptionListHead
)) {
1203 Status
= GetSelectionInputPopUp (MenuOption
);
1205 *OptionString
= AllocateZeroPool (BufferSize
);
1206 ASSERT (*OptionString
);
1208 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1209 if (OneOfOption
== NULL
) {
1210 if (SkipErrorValue
) {
1212 // Not report error, just get the correct option string info.
1214 Link
= GetFirstNode (&Question
->OptionListHead
);
1215 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1218 // Show error message
1221 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1222 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1225 // Force the Question value to be valid
1226 // Exit current DisplayForm with new value.
1228 Link
= GetFirstNode (&Question
->OptionListHead
);
1229 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1231 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1232 switch (gUserInput
->InputValue
.Type
) {
1233 case EFI_IFR_TYPE_NUM_SIZE_8
:
1234 gUserInput
->InputValue
.Value
.u8
= Option
->OptionOpCode
->Value
.u8
;
1236 case EFI_IFR_TYPE_NUM_SIZE_16
:
1237 CopyMem (&gUserInput
->InputValue
.Value
.u16
, &Option
->OptionOpCode
->Value
.u16
, sizeof (UINT16
));
1239 case EFI_IFR_TYPE_NUM_SIZE_32
:
1240 CopyMem (&gUserInput
->InputValue
.Value
.u32
, &Option
->OptionOpCode
->Value
.u32
, sizeof (UINT32
));
1242 case EFI_IFR_TYPE_NUM_SIZE_64
:
1243 CopyMem (&gUserInput
->InputValue
.Value
.u64
, &Option
->OptionOpCode
->Value
.u64
, sizeof (UINT64
));
1249 gUserInput
->SelectedStatement
= Question
;
1251 FreePool (*OptionString
);
1252 *OptionString
= NULL
;
1253 return EFI_NOT_FOUND
;
1257 Character
[0] = LEFT_ONEOF_DELIMITER
;
1258 NewStrCat (OptionString
[0], Character
);
1259 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1260 ASSERT (StringPtr
!= NULL
);
1261 NewStrCat (OptionString
[0], StringPtr
);
1262 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1263 NewStrCat (OptionString
[0], Character
);
1265 FreePool (StringPtr
);
1269 case EFI_IFR_CHECKBOX_OP
:
1272 // Since this is a BOOLEAN operation, flip it upon selection
1274 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1275 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
1278 // Perform inconsistent check
1280 return ValidateQuestion (Question
);
1282 *OptionString
= AllocateZeroPool (BufferSize
);
1283 ASSERT (*OptionString
);
1285 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1287 if (QuestionValue
->Value
.b
) {
1288 *(OptionString
[0] + 1) = CHECK_ON
;
1290 *(OptionString
[0] + 1) = CHECK_OFF
;
1292 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1296 case EFI_IFR_NUMERIC_OP
:
1301 Status
= GetNumericInput (MenuOption
);
1303 *OptionString
= AllocateZeroPool (BufferSize
);
1304 ASSERT (*OptionString
);
1306 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1311 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1312 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
1313 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1315 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1319 case EFI_IFR_DATE_OP
:
1322 // This is similar to numerics
1324 Status
= GetNumericInput (MenuOption
);
1326 *OptionString
= AllocateZeroPool (BufferSize
);
1327 ASSERT (*OptionString
);
1329 switch (MenuOption
->Sequence
) {
1331 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1332 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1333 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1337 SetUnicodeMem (OptionString
[0], 4, L
' ');
1338 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1339 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1343 SetUnicodeMem (OptionString
[0], 7, L
' ');
1344 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1345 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1351 case EFI_IFR_TIME_OP
:
1354 // This is similar to numerics
1356 Status
= GetNumericInput (MenuOption
);
1358 *OptionString
= AllocateZeroPool (BufferSize
);
1359 ASSERT (*OptionString
);
1361 switch (MenuOption
->Sequence
) {
1363 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1364 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1365 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1369 SetUnicodeMem (OptionString
[0], 4, L
' ');
1370 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1371 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1375 SetUnicodeMem (OptionString
[0], 7, L
' ');
1376 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1377 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1383 case EFI_IFR_STRING_OP
:
1385 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1387 CopyMem(StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1389 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1390 if (EFI_ERROR (Status
)) {
1391 FreePool (StringPtr
);
1395 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1396 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1397 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1398 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1399 FreePool (StringPtr
);
1400 return ValidateQuestion (Question
);
1402 *OptionString
= AllocateZeroPool (BufferSize
);
1403 ASSERT (*OptionString
);
1405 if (((CHAR16
*) Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1406 *(OptionString
[0]) = '_';
1408 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1409 BufferSize
= Question
->CurrentValue
.BufferLen
;
1411 CopyMem (OptionString
[0], (CHAR16
*) Question
->CurrentValue
.Buffer
, BufferSize
);
1416 case EFI_IFR_PASSWORD_OP
:
1418 Status
= PasswordProcess (MenuOption
);
1431 Process the help string: Split StringPtr to several lines of strings stored in
1432 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1434 @param StringPtr The entire help string.
1435 @param FormattedString The oupput formatted string.
1436 @param EachLineWidth The max string length of each line in the formatted string.
1437 @param RowCount TRUE: if Question is selected.
1442 IN CHAR16
*StringPtr
,
1443 OUT CHAR16
**FormattedString
,
1444 OUT UINT16
*EachLineWidth
,
1449 CHAR16
*OutputString
;
1454 UINT16 MaxStringLen
;
1465 // Set default help string width.
1467 LineWidth
= (UINT16
) (gHelpBlockWidth
- 1);
1470 // Get row number of the String.
1472 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1473 if (StringLen
> MaxStringLen
) {
1474 MaxStringLen
= StringLen
;
1478 FreePool (OutputString
);
1480 *EachLineWidth
= MaxStringLen
;
1482 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1483 ASSERT (*FormattedString
!= NULL
);
1486 // Generate formatted help string array.
1490 while((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1491 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1493 FreePool (OutputString
);