]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c
Check in the missing code.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / InputHandler.c
CommitLineData
7936fb6a 1/** @file\r
2Implementation for handling user input from the User Interfaces.\r
3\r
31585af4 4Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
7936fb6a 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
b9feb4bd 15#include "FormDisplay.h"\r
7936fb6a 16\r
b9feb4bd
ED
17/**\r
18 Get maximum and minimum info from this opcode.\r
19\r
20 @param OpCode Pointer to the current input opcode.\r
21 @param Minimum The minimum size info for this opcode.\r
22 @param Maximum The maximum size info for this opcode.\r
23\r
24**/\r
25VOID\r
26GetFieldFromOp (\r
27 IN EFI_IFR_OP_HEADER *OpCode,\r
28 OUT UINTN *Minimum,\r
29 OUT UINTN *Maximum\r
30 )\r
31{\r
32 EFI_IFR_STRING *StringOp;\r
33 EFI_IFR_PASSWORD *PasswordOp;\r
34 if (OpCode->OpCode == EFI_IFR_STRING_OP) {\r
35 StringOp = (EFI_IFR_STRING *) OpCode;\r
36 *Minimum = StringOp->MinSize;\r
37 *Maximum = StringOp->MaxSize; \r
38 } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
39 PasswordOp = (EFI_IFR_PASSWORD *) OpCode;\r
40 *Minimum = PasswordOp->MinSize;\r
41 *Maximum = PasswordOp->MaxSize; \r
42 } else {\r
43 *Minimum = 0;\r
44 *Maximum = 0; \r
45 }\r
46}\r
7936fb6a 47\r
48/**\r
49 Get string or password input from user.\r
50\r
51 @param MenuOption Pointer to the current input menu.\r
52 @param Prompt The prompt string shown on popup window.\r
da588638 53 @param StringPtr Old user input and destination for use input string.\r
7936fb6a 54\r
55 @retval EFI_SUCCESS If string input is read successfully\r
56 @retval EFI_DEVICE_ERROR If operation fails\r
57\r
58**/\r
59EFI_STATUS\r
60ReadString (\r
da588638
ED
61 IN UI_MENU_OPTION *MenuOption,\r
62 IN CHAR16 *Prompt,\r
63 IN OUT CHAR16 *StringPtr\r
7936fb6a 64 )\r
65{\r
66 EFI_STATUS Status;\r
67 EFI_INPUT_KEY Key;\r
68 CHAR16 NullCharacter;\r
69 UINTN ScreenSize;\r
70 CHAR16 Space[2];\r
71 CHAR16 KeyPad[2];\r
72 CHAR16 *TempString;\r
73 CHAR16 *BufferedString;\r
74 UINTN Index;\r
da588638 75 UINTN Index2;\r
7936fb6a 76 UINTN Count;\r
77 UINTN Start;\r
78 UINTN Top;\r
79 UINTN DimensionsWidth;\r
80 UINTN DimensionsHeight;\r
da588638 81 UINTN CurrentCursor;\r
7936fb6a 82 BOOLEAN CursorVisible;\r
83 UINTN Minimum;\r
84 UINTN Maximum;\r
b9feb4bd 85 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
7936fb6a 86 BOOLEAN IsPassword;\r
87\r
b9feb4bd
ED
88 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
89 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
7936fb6a 90\r
91 NullCharacter = CHAR_NULL;\r
92 ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);\r
93 Space[0] = L' ';\r
94 Space[1] = CHAR_NULL;\r
95\r
96 Question = MenuOption->ThisTag;\r
b9feb4bd 97 GetFieldFromOp(Question->OpCode, &Minimum, &Maximum);\r
7936fb6a 98\r
b9feb4bd 99 if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
7936fb6a 100 IsPassword = TRUE;\r
101 } else {\r
102 IsPassword = FALSE;\r
103 }\r
104\r
105 TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));\r
106 ASSERT (TempString);\r
107\r
108 if (ScreenSize < (Maximum + 1)) {\r
109 ScreenSize = Maximum + 1;\r
110 }\r
111\r
112 if ((ScreenSize + 2) > DimensionsWidth) {\r
113 ScreenSize = DimensionsWidth - 2;\r
114 }\r
115\r
116 BufferedString = AllocateZeroPool (ScreenSize * 2);\r
117 ASSERT (BufferedString);\r
118\r
b9feb4bd
ED
119 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
120 Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;\r
7936fb6a 121\r
122 //\r
123 // Display prompt for string\r
124 //\r
b9feb4bd 125 // CreateDialog (NULL, "", Prompt, Space, "", NULL);\r
3ebb9bdb 126 CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);\r
7936fb6a 127 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
128\r
129 CursorVisible = gST->ConOut->Mode->CursorVisible;\r
130 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
131\r
da588638
ED
132 CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;\r
133 if (CurrentCursor != 0) {\r
134 //\r
135 // Show the string which has beed saved before.\r
136 //\r
137 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
138 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
139\r
140 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
141 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
142 } else {\r
143 Index = 0;\r
144 }\r
145\r
146 if (IsPassword) {\r
147 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
148 }\r
149\r
150 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
151 BufferedString[Count] = StringPtr[Index];\r
152\r
153 if (IsPassword) {\r
b9feb4bd 154 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
da588638
ED
155 }\r
156 }\r
157\r
158 if (!IsPassword) {\r
159 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
160 }\r
161 \r
162 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
163 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
164 }\r
165 \r
7936fb6a 166 do {\r
167 Status = WaitForKeyStroke (&Key);\r
168 ASSERT_EFI_ERROR (Status);\r
169\r
170 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
171 switch (Key.UnicodeChar) {\r
172 case CHAR_NULL:\r
173 switch (Key.ScanCode) {\r
174 case SCAN_LEFT:\r
da588638
ED
175 if (CurrentCursor > 0) {\r
176 CurrentCursor--;\r
177 }\r
7936fb6a 178 break;\r
179\r
180 case SCAN_RIGHT:\r
da588638
ED
181 if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {\r
182 CurrentCursor++;\r
183 }\r
7936fb6a 184 break;\r
185\r
186 case SCAN_ESC:\r
f4113e1f 187 FreePool (TempString);\r
188 FreePool (BufferedString);\r
7936fb6a 189 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
190 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
191 return EFI_DEVICE_ERROR;\r
192\r
193 default:\r
194 break;\r
195 }\r
196\r
197 break;\r
198\r
199 case CHAR_CARRIAGE_RETURN:\r
200 if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {\r
201\r
f4113e1f 202 FreePool (TempString);\r
203 FreePool (BufferedString);\r
7936fb6a 204 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
205 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
206 return EFI_SUCCESS;\r
207 } else {\r
208 //\r
209 // Simply create a popup to tell the user that they had typed in too few characters.\r
210 // To save code space, we can then treat this as an error and return back to the menu.\r
211 //\r
212 do {\r
b9feb4bd 213 CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);\r
7936fb6a 214 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
215\r
f4113e1f 216 FreePool (TempString);\r
217 FreePool (BufferedString);\r
7936fb6a 218 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
219 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
220 return EFI_DEVICE_ERROR;\r
221 }\r
222\r
223 break;\r
224\r
225 case CHAR_BACKSPACE:\r
da588638
ED
226 if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {\r
227 for (Index = 0; Index < CurrentCursor - 1; Index++) {\r
7936fb6a 228 TempString[Index] = StringPtr[Index];\r
229 }\r
da588638
ED
230 Count = GetStringWidth (StringPtr) / 2 - 1;\r
231 if (Count >= CurrentCursor) {\r
232 for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {\r
233 TempString[Index] = StringPtr[Index2];\r
234 }\r
235 TempString[Index] = CHAR_NULL;\r
236 }\r
7936fb6a 237 //\r
238 // Effectively truncate string by 1 character\r
239 //\r
7936fb6a 240 StrCpy (StringPtr, TempString);\r
da588638 241 CurrentCursor --;\r
7936fb6a 242 }\r
243\r
244 default:\r
245 //\r
246 // If it is the beginning of the string, don't worry about checking maximum limits\r
247 //\r
248 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
249 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
da588638 250 CurrentCursor++;\r
7936fb6a 251 } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
252 KeyPad[0] = Key.UnicodeChar;\r
253 KeyPad[1] = CHAR_NULL;\r
da588638
ED
254 Count = GetStringWidth (StringPtr) / 2 - 1;\r
255 if (CurrentCursor < Count) {\r
256 for (Index = 0; Index < CurrentCursor; Index++) {\r
257 TempString[Index] = StringPtr[Index];\r
258 }\r
259 TempString[Index] = CHAR_NULL;\r
260 StrCat (TempString, KeyPad);\r
261 StrCat (TempString, StringPtr + CurrentCursor);\r
262 StrCpy (StringPtr, TempString);\r
263 } else {\r
264 StrCat (StringPtr, KeyPad);\r
265 }\r
266 CurrentCursor++;\r
7936fb6a 267 }\r
268\r
269 //\r
270 // If the width of the input string is now larger than the screen, we nee to\r
271 // adjust the index to start printing portions of the string\r
272 //\r
273 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
274 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
275\r
276 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
277 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
278 } else {\r
279 Index = 0;\r
280 }\r
281\r
282 if (IsPassword) {\r
283 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
284 }\r
285\r
286 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
287 BufferedString[Count] = StringPtr[Index];\r
288\r
289 if (IsPassword) {\r
b9feb4bd 290 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
7936fb6a 291 }\r
292 }\r
293\r
294 if (!IsPassword) {\r
295 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
296 }\r
297 break;\r
298 }\r
299\r
300 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
da588638 301 gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);\r
7936fb6a 302 } while (TRUE);\r
303\r
304}\r
305\r
38d6bb9e
ED
306/**\r
307 Adjust the value to the correct one. Rules follow the sample:\r
308 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
309 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
310\r
b9feb4bd 311 @param QuestionValue Pointer to current question.\r
38d6bb9e
ED
312 @param Sequence The sequence of the field in the question.\r
313**/\r
314VOID\r
315AdjustQuestionValue (\r
b9feb4bd 316 IN EFI_HII_VALUE *QuestionValue,\r
38d6bb9e
ED
317 IN UINT8 Sequence\r
318 )\r
319{\r
320 UINT8 Month;\r
321 UINT16 Year;\r
322 UINT8 Maximum;\r
323 UINT8 Minimum;\r
324\r
b9feb4bd
ED
325 Month = QuestionValue->Value.date.Month;\r
326 Year = QuestionValue->Value.date.Year;\r
38d6bb9e
ED
327 Minimum = 1;\r
328\r
329 switch (Month) {\r
330 case 2:\r
331 if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {\r
332 Maximum = 29;\r
333 } else {\r
334 Maximum = 28;\r
335 }\r
336 break;\r
337 case 4:\r
338 case 6:\r
339 case 9:\r
340 case 11:\r
341 Maximum = 30;\r
342 break;\r
343 default:\r
344 Maximum = 31;\r
345 break;\r
346 }\r
347\r
348 //\r
349 // Change the month area.\r
350 //\r
351 if (Sequence == 0) {\r
b9feb4bd
ED
352 if (QuestionValue->Value.date.Day > Maximum) {\r
353 QuestionValue->Value.date.Day = Maximum;\r
38d6bb9e
ED
354 }\r
355 }\r
356 \r
357 //\r
358 // Change the Year area.\r
359 //\r
360 if (Sequence == 2) {\r
b9feb4bd
ED
361 if (QuestionValue->Value.date.Day > Maximum) {\r
362 QuestionValue->Value.date.Day = Minimum;\r
38d6bb9e
ED
363 }\r
364 }\r
365}\r
7936fb6a 366\r
b9feb4bd
ED
367/**\r
368 Get field info from numeric opcode.\r
369\r
370 @param OpCode Pointer to the current input opcode.\r
371 @param Minimum The minimum size info for this opcode.\r
372 @param Maximum The maximum size info for this opcode.\r
373 @param Step The step size info for this opcode.\r
374 @param StorageWidth The storage width info for this opcode.\r
375\r
376**/\r
377VOID\r
378GetValueFromNum (\r
379 IN EFI_IFR_OP_HEADER *OpCode,\r
380 OUT UINT64 *Minimum,\r
381 OUT UINT64 *Maximum,\r
382 OUT UINT64 *Step,\r
383 OUT UINT16 *StorageWidth\r
384)\r
385{\r
386 EFI_IFR_NUMERIC *NumericOp;\r
387\r
388 NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
389 \r
390 switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
391 case EFI_IFR_NUMERIC_SIZE_1:\r
392 *Minimum = NumericOp->data.u8.MinValue;\r
393 *Maximum = NumericOp->data.u8.MaxValue;\r
394 *Step = NumericOp->data.u8.Step;\r
395 *StorageWidth = (UINT16) sizeof (UINT8);\r
396 break;\r
397 \r
398 case EFI_IFR_NUMERIC_SIZE_2:\r
399 *Minimum = NumericOp->data.u16.MinValue;\r
400 *Maximum = NumericOp->data.u16.MaxValue;\r
401 *Step = NumericOp->data.u16.Step;\r
402 *StorageWidth = (UINT16) sizeof (UINT16);\r
403 break;\r
404 \r
405 case EFI_IFR_NUMERIC_SIZE_4:\r
406 *Minimum = NumericOp->data.u32.MinValue;\r
407 *Maximum = NumericOp->data.u32.MaxValue;\r
408 *Step = NumericOp->data.u32.Step;\r
409 *StorageWidth = (UINT16) sizeof (UINT32);\r
410 break;\r
411 \r
412 case EFI_IFR_NUMERIC_SIZE_8:\r
413 *Minimum = NumericOp->data.u64.MinValue;\r
414 *Maximum = NumericOp->data.u64.MaxValue;\r
415 *Step = NumericOp->data.u64.Step;\r
416 *StorageWidth = (UINT16) sizeof (UINT64);\r
417 break;\r
418 \r
419 default:\r
420 break;\r
421 }\r
422\r
423 if (*Maximum == 0) {\r
424 *Maximum = (UINT64) -1;\r
425 }\r
426}\r
427\r
7936fb6a 428/**\r
429 This routine reads a numeric value from the user input.\r
430\r
7936fb6a 431 @param MenuOption Pointer to the current input menu.\r
432\r
433 @retval EFI_SUCCESS If numerical input is read successfully\r
434 @retval EFI_DEVICE_ERROR If operation fails\r
435\r
436**/\r
437EFI_STATUS\r
438GetNumericInput (\r
7936fb6a 439 IN UI_MENU_OPTION *MenuOption\r
440 )\r
441{\r
442 EFI_STATUS Status;\r
443 UINTN Column;\r
444 UINTN Row;\r
40a06b0c 445 CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];\r
446 CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];\r
447 UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];\r
7936fb6a 448 UINTN Count;\r
449 UINTN Loop;\r
450 BOOLEAN ManualInput;\r
451 BOOLEAN HexInput;\r
452 BOOLEAN DateOrTime;\r
453 UINTN InputWidth;\r
454 UINT64 EditValue;\r
455 UINT64 Step;\r
456 UINT64 Minimum;\r
457 UINT64 Maximum;\r
458 UINTN EraseLen;\r
459 UINT8 Digital;\r
460 EFI_INPUT_KEY Key;\r
461 EFI_HII_VALUE *QuestionValue;\r
b9feb4bd
ED
462 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
463 EFI_IFR_NUMERIC *NumericOp;\r
464 UINT16 StorageWidth;\r
7936fb6a 465\r
466 Column = MenuOption->OptCol;\r
467 Row = MenuOption->Row;\r
468 PreviousNumber[0] = 0;\r
469 Count = 0;\r
470 InputWidth = 0;\r
471 Digital = 0;\r
b9feb4bd
ED
472 StorageWidth = 0;\r
473 Minimum = 0;\r
474 Maximum = 0;\r
475 NumericOp = NULL;\r
7936fb6a 476\r
7936fb6a 477 Question = MenuOption->ThisTag;\r
b9feb4bd 478 QuestionValue = &Question->CurrentValue;\r
7936fb6a 479\r
e24adb18
ED
480 //\r
481 // Only two case, user can enter to this function: Enter and +/- case.\r
482 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT\r
483 //\r
484 ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);\r
485\r
b9feb4bd 486 if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
7936fb6a 487 DateOrTime = TRUE;\r
488 } else {\r
489 DateOrTime = FALSE;\r
490 }\r
491\r
492 //\r
493 // Prepare Value to be edit\r
494 //\r
495 EraseLen = 0;\r
496 EditValue = 0;\r
b9feb4bd 497 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
7936fb6a 498 Step = 1;\r
499 Minimum = 1;\r
500\r
501 switch (MenuOption->Sequence) {\r
502 case 0:\r
503 Maximum = 12;\r
504 EraseLen = 4;\r
505 EditValue = QuestionValue->Value.date.Month;\r
506 break;\r
507\r
508 case 1:\r
508b4e77
ED
509 switch (QuestionValue->Value.date.Month) {\r
510 case 2:\r
511 if ((QuestionValue->Value.date.Year % 4) == 0 && \r
c3342aa8
ED
512 ((QuestionValue->Value.date.Year % 100) != 0 || \r
513 (QuestionValue->Value.date.Year % 400) == 0)) {\r
508b4e77
ED
514 Maximum = 29;\r
515 } else {\r
516 Maximum = 28;\r
517 }\r
518 break;\r
519 case 4:\r
520 case 6:\r
521 case 9:\r
522 case 11:\r
523 Maximum = 30;\r
524 break;\r
525 default:\r
526 Maximum = 31;\r
527 break;\r
528 } \r
529\r
7936fb6a 530 EraseLen = 3;\r
531 EditValue = QuestionValue->Value.date.Day;\r
532 break;\r
533\r
534 case 2:\r
535 Maximum = 0xffff;\r
536 EraseLen = 5;\r
537 EditValue = QuestionValue->Value.date.Year;\r
538 break;\r
539\r
540 default:\r
541 break;\r
542 }\r
b9feb4bd 543 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
7936fb6a 544 Step = 1;\r
545 Minimum = 0;\r
546\r
547 switch (MenuOption->Sequence) {\r
548 case 0:\r
549 Maximum = 23;\r
550 EraseLen = 4;\r
551 EditValue = QuestionValue->Value.time.Hour;\r
552 break;\r
553\r
554 case 1:\r
555 Maximum = 59;\r
556 EraseLen = 3;\r
557 EditValue = QuestionValue->Value.time.Minute;\r
558 break;\r
559\r
560 case 2:\r
561 Maximum = 59;\r
562 EraseLen = 3;\r
563 EditValue = QuestionValue->Value.time.Second;\r
564 break;\r
565\r
566 default:\r
567 break;\r
568 }\r
569 } else {\r
b9feb4bd
ED
570 ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);\r
571 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;\r
572 GetValueFromNum(Question->OpCode, &Minimum, &Maximum, &Step, &StorageWidth);\r
7936fb6a 573 EditValue = QuestionValue->Value.u64;\r
b9feb4bd 574 EraseLen = gOptionBlockWidth;\r
7936fb6a 575 }\r
576\r
b9feb4bd
ED
577 if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL) &&\r
578 ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {\r
7936fb6a 579 HexInput = TRUE;\r
580 } else {\r
581 HexInput = FALSE;\r
582 }\r
583\r
e24adb18
ED
584 //\r
585 // Enter from "Enter" input, clear the old word showing.\r
586 //\r
7936fb6a 587 if (ManualInput) {\r
b9feb4bd 588 if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {\r
e24adb18 589 if (HexInput) {\r
b9feb4bd 590 InputWidth = StorageWidth * 2;\r
e24adb18 591 } else {\r
b9feb4bd 592 switch (StorageWidth) {\r
e24adb18
ED
593 case 1:\r
594 InputWidth = 3;\r
595 break;\r
596\r
597 case 2:\r
598 InputWidth = 5;\r
599 break;\r
600\r
601 case 4:\r
602 InputWidth = 10;\r
603 break;\r
604\r
605 case 8:\r
606 InputWidth = 20;\r
607 break;\r
608\r
609 default:\r
610 InputWidth = 0;\r
611 break;\r
612 }\r
613 }\r
7936fb6a 614\r
e24adb18
ED
615 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
616 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
617 ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);\r
618 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
619 InputText[InputWidth + 2] = L'\0';\r
7936fb6a 620\r
b9feb4bd 621 PrintStringAt (Column, Row, InputText);\r
e24adb18
ED
622 Column++;\r
623 }\r
7936fb6a 624\r
b9feb4bd 625 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
e24adb18
ED
626 if (MenuOption->Sequence == 2) {\r
627 InputWidth = 4;\r
628 } else {\r
629 InputWidth = 2;\r
630 }\r
7936fb6a 631\r
e24adb18
ED
632 if (MenuOption->Sequence == 0) {\r
633 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
634 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
635 } else {\r
636 SetUnicodeMem (InputText, InputWidth, L' ');\r
637 }\r
638\r
639 if (MenuOption->Sequence == 2) {\r
640 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
641 } else {\r
642 InputText[InputWidth + 1] = DATE_SEPARATOR;\r
643 }\r
644 InputText[InputWidth + 2] = L'\0';\r
645\r
b9feb4bd 646 PrintStringAt (Column, Row, InputText);\r
e24adb18
ED
647 if (MenuOption->Sequence == 0) {\r
648 Column++;\r
7936fb6a 649 }\r
650 }\r
651\r
b9feb4bd 652 if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
e24adb18 653 InputWidth = 2;\r
7936fb6a 654\r
e24adb18
ED
655 if (MenuOption->Sequence == 0) {\r
656 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
657 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
658 } else {\r
659 SetUnicodeMem (InputText, InputWidth, L' ');\r
660 }\r
661\r
662 if (MenuOption->Sequence == 2) {\r
663 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
664 } else {\r
665 InputText[InputWidth + 1] = TIME_SEPARATOR;\r
666 }\r
667 InputText[InputWidth + 2] = L'\0';\r
668\r
b9feb4bd 669 PrintStringAt (Column, Row, InputText);\r
e24adb18
ED
670 if (MenuOption->Sequence == 0) {\r
671 Column++;\r
672 }\r
673 }\r
7936fb6a 674 }\r
675\r
676 //\r
677 // First time we enter this handler, we need to check to see if\r
678 // we were passed an increment or decrement directive\r
679 //\r
680 do {\r
681 Key.UnicodeChar = CHAR_NULL;\r
682 if (gDirection != 0) {\r
683 Key.ScanCode = gDirection;\r
684 gDirection = 0;\r
685 goto TheKey2;\r
686 }\r
687\r
688 Status = WaitForKeyStroke (&Key);\r
689\r
690TheKey2:\r
691 switch (Key.UnicodeChar) {\r
692\r
693 case '+':\r
694 case '-':\r
695 if (Key.UnicodeChar == '+') {\r
696 Key.ScanCode = SCAN_RIGHT;\r
697 } else {\r
698 Key.ScanCode = SCAN_LEFT;\r
699 }\r
700 Key.UnicodeChar = CHAR_NULL;\r
701 goto TheKey2;\r
702\r
703 case CHAR_NULL:\r
704 switch (Key.ScanCode) {\r
705 case SCAN_LEFT:\r
706 case SCAN_RIGHT:\r
e24adb18 707 if (DateOrTime && !ManualInput) {\r
7936fb6a 708 //\r
709 // By setting this value, we will return back to the caller.\r
710 // We need to do this since an auto-refresh will destroy the adjustment\r
711 // based on what the real-time-clock is showing. So we always commit\r
712 // upon changing the value.\r
713 //\r
714 gDirection = SCAN_DOWN;\r
715 }\r
716\r
e24adb18 717 if ((Step != 0) && !ManualInput) {\r
7936fb6a 718 if (Key.ScanCode == SCAN_LEFT) {\r
508b4e77 719 if (EditValue >= Minimum + Step) {\r
7936fb6a 720 EditValue = EditValue - Step;\r
508b4e77 721 } else if (EditValue > Minimum){\r
7936fb6a 722 EditValue = Minimum;\r
508b4e77
ED
723 } else {\r
724 EditValue = Maximum;\r
7936fb6a 725 }\r
726 } else if (Key.ScanCode == SCAN_RIGHT) {\r
508b4e77
ED
727 if (EditValue + Step <= Maximum) {\r
728 EditValue = EditValue + Step;\r
729 } else if (EditValue < Maximum) {\r
7936fb6a 730 EditValue = Maximum;\r
508b4e77
ED
731 } else {\r
732 EditValue = Minimum;\r
7936fb6a 733 }\r
734 }\r
735\r
736 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
b9feb4bd 737 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
7936fb6a 738 if (MenuOption->Sequence == 2) {\r
739 //\r
740 // Year\r
741 //\r
7b9b2b92 742 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);\r
7936fb6a 743 } else {\r
744 //\r
745 // Month/Day\r
746 //\r
7b9b2b92 747 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
7936fb6a 748 }\r
749\r
750 if (MenuOption->Sequence == 0) {\r
e35eb8af 751 ASSERT (EraseLen >= 2);\r
7936fb6a 752 FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;\r
753 } else if (MenuOption->Sequence == 1) {\r
e35eb8af 754 ASSERT (EraseLen >= 1);\r
7936fb6a 755 FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;\r
756 }\r
b9feb4bd 757 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
7b9b2b92 758 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
7936fb6a 759\r
760 if (MenuOption->Sequence == 0) {\r
e35eb8af 761 ASSERT (EraseLen >= 2);\r
7936fb6a 762 FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;\r
763 } else if (MenuOption->Sequence == 1) {\r
e35eb8af 764 ASSERT (EraseLen >= 1);\r
7936fb6a 765 FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;\r
766 }\r
767 } else {\r
768 QuestionValue->Value.u64 = EditValue;\r
769 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
770 }\r
771\r
b9feb4bd 772 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
7936fb6a 773 for (Loop = 0; Loop < EraseLen; Loop++) {\r
b9feb4bd 774 PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
7936fb6a 775 }\r
b9feb4bd 776 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
7936fb6a 777\r
778 if (MenuOption->Sequence == 0) {\r
779 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
780 Column = MenuOption->OptCol + 1;\r
781 }\r
782\r
783 PrintStringAt (Column, Row, FormattedNumber);\r
784\r
785 if (!DateOrTime || MenuOption->Sequence == 2) {\r
b9feb4bd 786 PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);\r
7936fb6a 787 }\r
788 }\r
e8e36190 789\r
790 goto EnterCarriageReturn;\r
7936fb6a 791 break;\r
792\r
793 case SCAN_UP:\r
794 case SCAN_DOWN:\r
795 goto EnterCarriageReturn;\r
796\r
797 case SCAN_ESC:\r
798 return EFI_DEVICE_ERROR;\r
799\r
800 default:\r
801 break;\r
802 }\r
803\r
804 break;\r
805\r
806EnterCarriageReturn:\r
807\r
808 case CHAR_CARRIAGE_RETURN:\r
e6063a95
ED
809 //\r
810 // Validate input value with Minimum value.\r
811 //\r
812 if (EditValue < Minimum) {\r
b9feb4bd 813 UpdateStatusBar (INPUT_ERROR, TRUE);\r
e6063a95
ED
814 break;\r
815 } else {\r
b9feb4bd 816 UpdateStatusBar (INPUT_ERROR, FALSE);\r
e6063a95 817 }\r
b9feb4bd
ED
818 \r
819 CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));\r
820 QuestionValue = &gUserInput->InputValue;\r
7936fb6a 821 //\r
822 // Store Edit value back to Question\r
823 //\r
b9feb4bd 824 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
7936fb6a 825 switch (MenuOption->Sequence) {\r
826 case 0:\r
827 QuestionValue->Value.date.Month = (UINT8) EditValue;\r
828 break;\r
829\r
830 case 1:\r
831 QuestionValue->Value.date.Day = (UINT8) EditValue;\r
832 break;\r
833\r
834 case 2:\r
835 QuestionValue->Value.date.Year = (UINT16) EditValue;\r
836 break;\r
837\r
838 default:\r
839 break;\r
840 }\r
b9feb4bd 841 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
7936fb6a 842 switch (MenuOption->Sequence) {\r
843 case 0:\r
844 QuestionValue->Value.time.Hour = (UINT8) EditValue;\r
845 break;\r
846\r
847 case 1:\r
848 QuestionValue->Value.time.Minute = (UINT8) EditValue;\r
849 break;\r
850\r
851 case 2:\r
852 QuestionValue->Value.time.Second = (UINT8) EditValue;\r
853 break;\r
854\r
855 default:\r
856 break;\r
857 }\r
858 } else {\r
859 //\r
860 // Numeric\r
861 //\r
862 QuestionValue->Value.u64 = EditValue;\r
863 }\r
864\r
38d6bb9e
ED
865 //\r
866 // Adjust the value to the correct one.\r
867 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
868 // 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
869 //\r
b9feb4bd 870 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP && \r
38d6bb9e 871 (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {\r
b9feb4bd 872 AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);\r
7936fb6a 873 }\r
874\r
b9feb4bd 875 return ValidateQuestion (Question);\r
7936fb6a 876 break;\r
877\r
878 case CHAR_BACKSPACE:\r
879 if (ManualInput) {\r
880 if (Count == 0) {\r
881 break;\r
882 }\r
883 //\r
884 // Remove a character\r
885 //\r
886 EditValue = PreviousNumber[Count - 1];\r
b9feb4bd 887 UpdateStatusBar (INPUT_ERROR, FALSE);\r
7936fb6a 888 Count--;\r
889 Column--;\r
b9feb4bd 890 PrintStringAt (Column, Row, L" ");\r
7936fb6a 891 }\r
892 break;\r
893\r
894 default:\r
895 if (ManualInput) {\r
896 if (HexInput) {\r
63d55bb9
LG
897 if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {\r
898 Digital = (UINT8) (Key.UnicodeChar - L'0');\r
899 } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {\r
900 Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);\r
901 } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
902 Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
903 } else {\r
b9feb4bd 904 UpdateStatusBar (INPUT_ERROR, TRUE);\r
7936fb6a 905 break;\r
906 }\r
907 } else {\r
908 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
b9feb4bd 909 UpdateStatusBar (INPUT_ERROR, TRUE);\r
7936fb6a 910 break;\r
911 }\r
912 }\r
913\r
914 //\r
915 // If Count exceed input width, there is no way more is valid\r
916 //\r
917 if (Count >= InputWidth) {\r
918 break;\r
919 }\r
920 //\r
921 // Someone typed something valid!\r
922 //\r
923 if (Count != 0) {\r
924 if (HexInput) {\r
925 EditValue = LShiftU64 (EditValue, 4) + Digital;\r
926 } else {\r
927 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');\r
928 }\r
929 } else {\r
930 if (HexInput) {\r
931 EditValue = Digital;\r
932 } else {\r
933 EditValue = Key.UnicodeChar - L'0';\r
934 }\r
935 }\r
936\r
937 if (EditValue > Maximum) {\r
b9feb4bd 938 UpdateStatusBar (INPUT_ERROR, TRUE);\r
40a06b0c 939 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
7936fb6a 940 EditValue = PreviousNumber[Count];\r
941 break;\r
942 } else {\r
b9feb4bd 943 UpdateStatusBar (INPUT_ERROR, FALSE);\r
7936fb6a 944 }\r
945\r
946 Count++;\r
bc166db3 947 ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));\r
7936fb6a 948 PreviousNumber[Count] = EditValue;\r
949\r
b9feb4bd 950 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
7936fb6a 951 PrintCharAt (Column, Row, Key.UnicodeChar);\r
952 Column++;\r
953 }\r
954 break;\r
955 }\r
956 } while (TRUE);\r
b9feb4bd
ED
957}\r
958\r
959/**\r
960 Adjust option order base on the question value.\r
961\r
962 @param Question Pointer to current question.\r
963 @param PopUpMenuLines The line number of the pop up menu.\r
964\r
965 @retval EFI_SUCCESS If Option input is processed successfully\r
966 @retval EFI_DEVICE_ERROR If operation fails\r
967\r
968**/\r
969EFI_STATUS\r
970AdjustOptionOrder (\r
971 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
972 OUT UINTN *PopUpMenuLines\r
973 )\r
974{\r
975 UINTN Index;\r
976 EFI_IFR_ORDERED_LIST *OrderList;\r
977 UINT8 *ValueArray;\r
978 UINT8 ValueType;\r
979 LIST_ENTRY *Link;\r
980 DISPLAY_QUESTION_OPTION *OneOfOption;\r
981 EFI_HII_VALUE *HiiValueArray;\r
982\r
983 Link = GetFirstNode (&Question->OptionListHead);\r
984 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
985 ValueArray = Question->CurrentValue.Buffer;\r
986 ValueType = OneOfOption->OptionOpCode->Type;\r
987 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
988\r
989 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
990 if (GetArrayData (ValueArray, ValueType, Index) == 0) {\r
991 break;\r
992 }\r
993 }\r
994 \r
995 *PopUpMenuLines = Index;\r
996 \r
997 //\r
998 // Prepare HiiValue array\r
999 // \r
1000 HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));\r
1001 ASSERT (HiiValueArray != NULL);\r
1002\r
1003 for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
1004 HiiValueArray[Index].Type = ValueType;\r
1005 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1006 }\r
1007 \r
1008 for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
1009 OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);\r
1010 if (OneOfOption == NULL) {\r
1011 return EFI_NOT_FOUND;\r
1012 }\r
1013 \r
1014 RemoveEntryList (&OneOfOption->Link);\r
1015 \r
1016 //\r
1017 // Insert to head.\r
1018 //\r
1019 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);\r
1020 }\r
1021 \r
1022 FreePool (HiiValueArray);\r
7936fb6a 1023\r
b9feb4bd 1024 return EFI_SUCCESS;\r
7936fb6a 1025}\r
1026\r
b9feb4bd
ED
1027/**\r
1028 Base on the type to compare the value.\r
1029\r
1030 @param Value1 The first value need to compare.\r
1031 @param Value2 The second value need to compare.\r
1032 @param Type The value type for above two values.\r
1033\r
1034 @retval TRUE The two value are same.\r
1035 @retval FALSE The two value are different.\r
1036\r
1037**/\r
1038BOOLEAN\r
1039IsValuesEqual (\r
1040 IN EFI_IFR_TYPE_VALUE *Value1,\r
1041 IN EFI_IFR_TYPE_VALUE *Value2,\r
1042 IN UINT8 Type\r
1043 )\r
1044{\r
1045 switch (Type) {\r
1046 case EFI_IFR_TYPE_BOOLEAN:\r
1047 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1048 return (BOOLEAN) (Value1->u8 == Value2->u8);\r
1049 \r
1050 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1051 return (BOOLEAN) (Value1->u16 == Value2->u16);\r
1052 \r
1053 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1054 return (BOOLEAN) (Value1->u32 == Value2->u32);\r
1055 \r
1056 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1057 return (BOOLEAN) (Value1->u64 == Value2->u64);\r
1058\r
1059 default:\r
1060 ASSERT (FALSE);\r
1061 return FALSE;\r
1062 }\r
1063}\r
1064\r
1065/**\r
1066 Base on the type to set the value.\r
1067\r
1068 @param Dest The dest value.\r
1069 @param Source The source value.\r
1070 @param Type The value type for above two values.\r
1071\r
1072**/\r
1073VOID\r
1074SetValuesByType (\r
1075 OUT EFI_IFR_TYPE_VALUE *Dest,\r
1076 IN EFI_IFR_TYPE_VALUE *Source,\r
1077 IN UINT8 Type\r
1078 )\r
1079{\r
1080 switch (Type) {\r
1081 case EFI_IFR_TYPE_BOOLEAN:\r
1082 Dest->b = Source->b;\r
1083 break;\r
1084\r
1085 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1086 Dest->u8 = Source->u8;\r
1087 break;\r
1088\r
1089 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1090 Dest->u16 = Source->u16;\r
1091 break;\r
1092\r
1093 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1094 Dest->u32 = Source->u32;\r
1095 break;\r
1096\r
1097 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1098 Dest->u64 = Source->u64;\r
1099 break;\r
1100\r
1101 default:\r
1102 ASSERT (FALSE);\r
1103 break;\r
1104 }\r
1105}\r
7936fb6a 1106\r
1107/**\r
1108 Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
1109\r
7936fb6a 1110 @param MenuOption Pointer to the current input menu.\r
1111\r
1112 @retval EFI_SUCCESS If Option input is processed successfully\r
1113 @retval EFI_DEVICE_ERROR If operation fails\r
1114\r
1115**/\r
1116EFI_STATUS\r
1117GetSelectionInputPopUp (\r
7936fb6a 1118 IN UI_MENU_OPTION *MenuOption\r
1119 )\r
1120{\r
1121 EFI_STATUS Status;\r
1122 EFI_INPUT_KEY Key;\r
1123 UINTN Index;\r
1124 CHAR16 *StringPtr;\r
1125 CHAR16 *TempStringPtr;\r
1126 UINTN Index2;\r
1127 UINTN TopOptionIndex;\r
1128 UINTN HighlightOptionIndex;\r
1129 UINTN Start;\r
1130 UINTN End;\r
1131 UINTN Top;\r
1132 UINTN Bottom;\r
1133 UINTN PopUpMenuLines;\r
1134 UINTN MenuLinesInView;\r
1135 UINTN PopUpWidth;\r
1136 CHAR16 Character;\r
1137 INT32 SavedAttribute;\r
1138 BOOLEAN ShowDownArrow;\r
1139 BOOLEAN ShowUpArrow;\r
1140 UINTN DimensionsWidth;\r
1141 LIST_ENTRY *Link;\r
1142 BOOLEAN OrderedList;\r
1143 UINT8 *ValueArray;\r
b9feb4bd 1144 UINT8 *ReturnValue;\r
d02847d3 1145 UINT8 ValueType;\r
7936fb6a 1146 EFI_HII_VALUE HiiValue;\r
b9feb4bd
ED
1147 DISPLAY_QUESTION_OPTION *OneOfOption;\r
1148 DISPLAY_QUESTION_OPTION *CurrentOption;\r
1149 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
8f420676 1150 INTN Result;\r
b9feb4bd 1151 EFI_IFR_ORDERED_LIST *OrderList;\r
7936fb6a 1152\r
b9feb4bd 1153 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
7936fb6a 1154\r
1155 ValueArray = NULL;\r
d02847d3 1156 ValueType = 0;\r
7936fb6a 1157 CurrentOption = NULL;\r
1158 ShowDownArrow = FALSE;\r
1159 ShowUpArrow = FALSE;\r
1160\r
1161 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
1162 ASSERT (StringPtr);\r
1163\r
b9feb4bd
ED
1164 ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));\r
1165\r
7936fb6a 1166 Question = MenuOption->ThisTag;\r
b9feb4bd
ED
1167 if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
1168 Link = GetFirstNode (&Question->OptionListHead);\r
1169 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1170 ValueArray = Question->CurrentValue.Buffer;\r
1171 ValueType = OneOfOption->OptionOpCode->Type;\r
7936fb6a 1172 OrderedList = TRUE;\r
b9feb4bd 1173 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
7936fb6a 1174 } else {\r
1175 OrderedList = FALSE;\r
b9feb4bd 1176 OrderList = NULL;\r
7936fb6a 1177 }\r
1178\r
1179 //\r
1180 // Calculate Option count\r
1181 //\r
b9feb4bd 1182 PopUpMenuLines = 0;\r
7936fb6a 1183 if (OrderedList) {\r
b9feb4bd 1184 AdjustOptionOrder(Question, &PopUpMenuLines);\r
7936fb6a 1185 } else {\r
7936fb6a 1186 Link = GetFirstNode (&Question->OptionListHead);\r
1187 while (!IsNull (&Question->OptionListHead, Link)) {\r
b9feb4bd 1188 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
7936fb6a 1189 PopUpMenuLines++;\r
82612023 1190 Link = GetNextNode (&Question->OptionListHead, Link);\r
82612023 1191 }\r
7936fb6a 1192 }\r
1193\r
1194 //\r
1195 // Get the number of one of options present and its size\r
1196 //\r
1197 PopUpWidth = 0;\r
1198 HighlightOptionIndex = 0;\r
1199 Link = GetFirstNode (&Question->OptionListHead);\r
1200 for (Index = 0; Index < PopUpMenuLines; Index++) {\r
b9feb4bd 1201 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
7936fb6a 1202\r
b9feb4bd 1203 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
7936fb6a 1204 if (StrLen (StringPtr) > PopUpWidth) {\r
1205 PopUpWidth = StrLen (StringPtr);\r
1206 }\r
f4113e1f 1207 FreePool (StringPtr);\r
b9feb4bd
ED
1208 HiiValue.Type = OneOfOption->OptionOpCode->Type;\r
1209 SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);\r
1210 if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
7936fb6a 1211 //\r
1212 // Find current selected Option for OneOf\r
1213 //\r
1214 HighlightOptionIndex = Index;\r
1215 }\r
b9feb4bd
ED
1216\r
1217 Link = GetNextNode (&Question->OptionListHead, Link);\r
7936fb6a 1218 }\r
1219\r
1220 //\r
1221 // Perform popup menu initialization.\r
1222 //\r
1223 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
1224\r
1225 SavedAttribute = gST->ConOut->Mode->Attribute;\r
b9feb4bd 1226 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
7936fb6a 1227\r
1228 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
1229 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
1230 }\r
1231\r
b9feb4bd 1232 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;\r
7936fb6a 1233 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
b9feb4bd
ED
1234 Top = gStatementDimensions.TopRow;\r
1235 Bottom = gStatementDimensions.BottomRow - 1;\r
7936fb6a 1236\r
1237 MenuLinesInView = Bottom - Top - 1;\r
1238 if (MenuLinesInView >= PopUpMenuLines) {\r
1239 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
1240 Bottom = Top + PopUpMenuLines + 1;\r
1241 } else {\r
1242 ShowDownArrow = TRUE;\r
1243 }\r
1244\r
1245 if (HighlightOptionIndex > (MenuLinesInView - 1)) {\r
1246 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;\r
1247 } else {\r
1248 TopOptionIndex = 0;\r
1249 }\r
1250\r
1251 do {\r
1252 //\r
1253 // Clear that portion of the screen\r
1254 //\r
b9feb4bd 1255 ClearLines (Start, End, Top, Bottom, GetPopupColor ());\r
7936fb6a 1256\r
1257 //\r
1258 // Draw "One of" pop-up menu\r
1259 //\r
1260 Character = BOXDRAW_DOWN_RIGHT;\r
1261 PrintCharAt (Start, Top, Character);\r
1262 for (Index = Start; Index + 2 < End; Index++) {\r
1263 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1264 Character = GEOMETRICSHAPE_UP_TRIANGLE;\r
1265 } else {\r
1266 Character = BOXDRAW_HORIZONTAL;\r
1267 }\r
1268\r
b9feb4bd 1269 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
7936fb6a 1270 }\r
1271\r
1272 Character = BOXDRAW_DOWN_LEFT;\r
b9feb4bd 1273 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
7936fb6a 1274 Character = BOXDRAW_VERTICAL;\r
1275 for (Index = Top + 1; Index < Bottom; Index++) {\r
1276 PrintCharAt (Start, Index, Character);\r
1277 PrintCharAt (End - 1, Index, Character);\r
1278 }\r
1279\r
1280 //\r
1281 // Move to top Option\r
1282 //\r
1283 Link = GetFirstNode (&Question->OptionListHead);\r
1284 for (Index = 0; Index < TopOptionIndex; Index++) {\r
1285 Link = GetNextNode (&Question->OptionListHead, Link);\r
1286 }\r
1287\r
1288 //\r
1289 // Display the One of options\r
1290 //\r
1291 Index2 = Top + 1;\r
1292 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {\r
b9feb4bd 1293 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
7936fb6a 1294 Link = GetNextNode (&Question->OptionListHead, Link);\r
1295\r
b9feb4bd 1296 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
04eb20aa 1297 ASSERT (StringPtr != NULL);\r
7936fb6a 1298 //\r
1299 // If the string occupies multiple lines, truncate it to fit in one line,\r
1300 // and append a "..." for indication.\r
1301 //\r
1302 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
1303 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
1304 ASSERT ( TempStringPtr != NULL );\r
1305 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
f4113e1f 1306 FreePool (StringPtr);\r
7936fb6a 1307 StringPtr = TempStringPtr;\r
1308 StrCat (StringPtr, L"...");\r
1309 }\r
1310\r
1311 if (Index == HighlightOptionIndex) {\r
1312 //\r
1313 // Highlight the selected one\r
1314 //\r
1315 CurrentOption = OneOfOption;\r
1316\r
b9feb4bd 1317 gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());\r
7936fb6a 1318 PrintStringAt (Start + 2, Index2, StringPtr);\r
b9feb4bd 1319 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
7936fb6a 1320 } else {\r
b9feb4bd 1321 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
7936fb6a 1322 PrintStringAt (Start + 2, Index2, StringPtr);\r
1323 }\r
1324\r
1325 Index2++;\r
f4113e1f 1326 FreePool (StringPtr);\r
7936fb6a 1327 }\r
1328\r
1329 Character = BOXDRAW_UP_RIGHT;\r
1330 PrintCharAt (Start, Bottom, Character);\r
1331 for (Index = Start; Index + 2 < End; Index++) {\r
1332 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1333 Character = GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1334 } else {\r
1335 Character = BOXDRAW_HORIZONTAL;\r
1336 }\r
1337\r
b9feb4bd 1338 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
7936fb6a 1339 }\r
1340\r
1341 Character = BOXDRAW_UP_LEFT;\r
b9feb4bd 1342 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
7936fb6a 1343\r
1344 //\r
1345 // Get User selection\r
1346 //\r
1347 Key.UnicodeChar = CHAR_NULL;\r
1348 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1349 Key.ScanCode = gDirection;\r
1350 gDirection = 0;\r
1351 goto TheKey;\r
1352 }\r
1353\r
1354 Status = WaitForKeyStroke (&Key);\r
1355\r
1356TheKey:\r
1357 switch (Key.UnicodeChar) {\r
1358 case '+':\r
1359 if (OrderedList) {\r
1360 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1361 //\r
1362 // Highlight reaches the top of the popup window, scroll one menu item.\r
1363 //\r
1364 TopOptionIndex--;\r
1365 ShowDownArrow = TRUE;\r
1366 }\r
1367\r
1368 if (TopOptionIndex == 0) {\r
1369 ShowUpArrow = FALSE;\r
1370 }\r
1371\r
1372 if (HighlightOptionIndex > 0) {\r
1373 HighlightOptionIndex--;\r
1374\r
40a06b0c 1375 ASSERT (CurrentOption != NULL);\r
7936fb6a 1376 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);\r
1377 }\r
1378 }\r
1379 break;\r
1380\r
1381 case '-':\r
1382 //\r
1383 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1384 // to create an ordered list of items\r
1385 //\r
1386 if (OrderedList) {\r
1387 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1388 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1389 //\r
1390 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1391 //\r
1392 TopOptionIndex++;\r
1393 ShowUpArrow = TRUE;\r
1394 }\r
1395\r
1396 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1397 ShowDownArrow = FALSE;\r
1398 }\r
1399\r
1400 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1401 HighlightOptionIndex++;\r
1402\r
40a06b0c 1403 ASSERT (CurrentOption != NULL);\r
7936fb6a 1404 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);\r
1405 }\r
1406 }\r
1407 break;\r
1408\r
1409 case CHAR_NULL:\r
1410 switch (Key.ScanCode) {\r
1411 case SCAN_UP:\r
1412 case SCAN_DOWN:\r
1413 if (Key.ScanCode == SCAN_UP) {\r
1414 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1415 //\r
1416 // Highlight reaches the top of the popup window, scroll one menu item.\r
1417 //\r
1418 TopOptionIndex--;\r
1419 ShowDownArrow = TRUE;\r
1420 }\r
1421\r
1422 if (TopOptionIndex == 0) {\r
1423 ShowUpArrow = FALSE;\r
1424 }\r
1425\r
1426 if (HighlightOptionIndex > 0) {\r
1427 HighlightOptionIndex--;\r
1428 }\r
1429 } else {\r
1430 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1431 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1432 //\r
1433 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1434 //\r
1435 TopOptionIndex++;\r
1436 ShowUpArrow = TRUE;\r
1437 }\r
1438\r
1439 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1440 ShowDownArrow = FALSE;\r
1441 }\r
1442\r
1443 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1444 HighlightOptionIndex++;\r
1445 }\r
1446 }\r
1447 break;\r
1448\r
1449 case SCAN_ESC:\r
1450 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1451\r
1452 //\r
1453 // Restore link list order for orderedlist\r
1454 //\r
1455 if (OrderedList) {\r
d02847d3 1456 HiiValue.Type = ValueType;\r
7936fb6a 1457 HiiValue.Value.u64 = 0;\r
b9feb4bd 1458 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
d02847d3 1459 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1460 if (HiiValue.Value.u64 == 0) {\r
7936fb6a 1461 break;\r
1462 }\r
1463\r
1464 OneOfOption = ValueToOption (Question, &HiiValue);\r
1465 if (OneOfOption == NULL) {\r
1466 return EFI_NOT_FOUND;\r
1467 }\r
1468\r
1469 RemoveEntryList (&OneOfOption->Link);\r
1470 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
1471 }\r
1472 }\r
1473\r
7936fb6a 1474 return EFI_DEVICE_ERROR;\r
1475\r
1476 default:\r
1477 break;\r
1478 }\r
1479\r
1480 break;\r
1481\r
1482 case CHAR_CARRIAGE_RETURN:\r
1483 //\r
1484 // return the current selection\r
1485 //\r
1486 if (OrderedList) {\r
b9feb4bd
ED
1487 ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
1488 ASSERT (ReturnValue != NULL);\r
7936fb6a 1489 Index = 0;\r
1490 Link = GetFirstNode (&Question->OptionListHead);\r
1491 while (!IsNull (&Question->OptionListHead, Link)) {\r
b9feb4bd 1492 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
82612023
ED
1493 Link = GetNextNode (&Question->OptionListHead, Link);\r
1494\r
b9feb4bd 1495 SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);\r
7936fb6a 1496\r
1497 Index++;\r
b9feb4bd 1498 if (Index > OrderList->MaxContainers) {\r
7936fb6a 1499 break;\r
1500 }\r
7936fb6a 1501 }\r
b9feb4bd
ED
1502 if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {\r
1503 FreePool (ReturnValue);\r
1504 return EFI_DEVICE_ERROR;\r
1505 } else {\r
1506 gUserInput->InputValue.Buffer = ReturnValue;\r
1507 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1508 Status = EFI_SUCCESS;\r
1509 }\r
7936fb6a 1510 } else {\r
40a06b0c 1511 ASSERT (CurrentOption != NULL);\r
b9feb4bd
ED
1512 gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;\r
1513 if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {\r
1514 return EFI_DEVICE_ERROR;\r
1515 } else {\r
1516 SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);\r
1517 Status = EFI_SUCCESS;\r
1518 }\r
7936fb6a 1519 }\r
1520\r
1521 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
7936fb6a 1522\r
b9feb4bd
ED
1523 return ValidateQuestion (Question);\r
1524 \r
7936fb6a 1525 default:\r
1526 break;\r
1527 }\r
1528 } while (TRUE);\r
1529\r
1530}\r
1531\r