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