]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
1. add EFI Firmware Management protocol definition in MdePkg.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
CommitLineData
7936fb6a 1/** @file\r
2Utility functions for User Interface functions.\r
3\r
19b15d63 4Copyright (c) 2004 - 2008, Intel Corporation\r
7936fb6a 5All rights reserved. This program and the accompanying materials\r
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
15#include "Ui.h"\r
16#include "Setup.h"\r
17\r
18LIST_ENTRY Menu;\r
19LIST_ENTRY gMenuList;\r
20MENU_REFRESH_ENTRY *gMenuRefreshHead;\r
21\r
22//\r
23// Search table for UiDisplayMenu()\r
24//\r
25SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
26 {\r
27 SCAN_UP,\r
28 UiUp,\r
29 },\r
30 {\r
31 SCAN_DOWN,\r
32 UiDown,\r
33 },\r
34 {\r
35 SCAN_PAGE_UP,\r
36 UiPageUp,\r
37 },\r
38 {\r
39 SCAN_PAGE_DOWN,\r
40 UiPageDown,\r
41 },\r
42 {\r
43 SCAN_ESC,\r
44 UiReset,\r
45 },\r
46 {\r
47 SCAN_F2,\r
48 UiPrevious,\r
49 },\r
50 {\r
51 SCAN_LEFT,\r
52 UiLeft,\r
53 },\r
54 {\r
55 SCAN_RIGHT,\r
56 UiRight,\r
57 },\r
58 {\r
59 SCAN_F9,\r
60 UiDefault,\r
61 },\r
62 {\r
63 SCAN_F10,\r
64 UiSave\r
65 }\r
66};\r
67\r
68SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
69 {\r
70 UiNoOperation,\r
71 CfUiNoOperation,\r
72 },\r
73 {\r
74 UiDefault,\r
75 CfUiDefault,\r
76 },\r
77 {\r
78 UiSelect,\r
79 CfUiSelect,\r
80 },\r
81 {\r
82 UiUp,\r
83 CfUiUp,\r
84 },\r
85 {\r
86 UiDown,\r
87 CfUiDown,\r
88 },\r
89 {\r
90 UiLeft,\r
91 CfUiLeft,\r
92 },\r
93 {\r
94 UiRight,\r
95 CfUiRight,\r
96 },\r
97 {\r
98 UiReset,\r
99 CfUiReset,\r
100 },\r
101 {\r
102 UiSave,\r
103 CfUiSave,\r
104 },\r
105 {\r
106 UiPrevious,\r
107 CfUiPrevious,\r
108 },\r
109 {\r
110 UiPageUp,\r
111 CfUiPageUp,\r
112 },\r
113 {\r
114 UiPageDown,\r
115 CfUiPageDown\r
116 }\r
117};\r
118\r
19b15d63 119BOOLEAN mInputError;\r
aa79b0b3 120BOOLEAN GetLineByWidthFinished = FALSE;\r
19b15d63 121\r
7936fb6a 122\r
123/**\r
124 Set Buffer to Value for Size bytes.\r
125\r
126 @param Buffer Memory to set.\r
127 @param Size Number of bytes to set\r
128 @param Value Value of the set operation.\r
129\r
2e95d2b7 130 @return Value.\r
131\r
7936fb6a 132**/\r
133VOID\r
134SetUnicodeMem (\r
135 IN VOID *Buffer,\r
136 IN UINTN Size,\r
137 IN CHAR16 Value\r
138 )\r
139{\r
140 CHAR16 *Ptr;\r
141\r
142 Ptr = Buffer;\r
143 while ((Size--) != 0) {\r
144 *(Ptr++) = Value;\r
145 }\r
146}\r
147\r
148\r
149/**\r
150 Initialize Menu option list.\r
151\r
152**/\r
153VOID\r
154UiInitMenu (\r
155 VOID\r
156 )\r
157{\r
158 InitializeListHead (&Menu);\r
159}\r
160\r
161\r
162/**\r
163 Initialize Menu option list.\r
164\r
165**/\r
166VOID\r
167UiInitMenuList (\r
168 VOID\r
169 )\r
170{\r
171 InitializeListHead (&gMenuList);\r
172}\r
173\r
174\r
175/**\r
176 Remove a Menu in list, and return FormId/QuestionId for previous Menu.\r
177\r
178 @param Selection Menu selection.\r
179\r
180**/\r
181VOID\r
182UiRemoveMenuListEntry (\r
183 OUT UI_MENU_SELECTION *Selection\r
184 )\r
185{\r
186 UI_MENU_LIST *UiMenuList;\r
187\r
188 if (!IsListEmpty (&gMenuList)) {\r
189 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
190\r
191 Selection->FormId = UiMenuList->FormId;\r
192 Selection->QuestionId = UiMenuList->QuestionId;\r
193 RemoveEntryList (&UiMenuList->MenuLink);\r
f4113e1f 194 FreePool (UiMenuList);\r
7936fb6a 195 }\r
196}\r
197\r
198\r
199/**\r
200 Free Menu option linked list.\r
201\r
202**/\r
203VOID\r
204UiFreeMenuList (\r
205 VOID\r
206 )\r
207{\r
208 UI_MENU_LIST *UiMenuList;\r
209\r
210 while (!IsListEmpty (&gMenuList)) {\r
211 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
212 RemoveEntryList (&UiMenuList->MenuLink);\r
f4113e1f 213 FreePool (UiMenuList);\r
7936fb6a 214 }\r
215}\r
216\r
217\r
218/**\r
219 Add one menu entry to the linked lst\r
220\r
221 @param Selection Menu selection.\r
222\r
223**/\r
224VOID\r
225UiAddMenuListEntry (\r
226 IN UI_MENU_SELECTION *Selection\r
227 )\r
228{\r
229 UI_MENU_LIST *UiMenuList;\r
230\r
231 UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
232 ASSERT (UiMenuList != NULL);\r
233\r
234 UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
235 UiMenuList->FormId = Selection->FormId;\r
236 UiMenuList->QuestionId = Selection->QuestionId;\r
237\r
238 InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
239}\r
240\r
241\r
242/**\r
243 Free Menu option linked list.\r
244\r
245**/\r
246VOID\r
247UiFreeMenu (\r
248 VOID\r
249 )\r
250{\r
251 UI_MENU_OPTION *MenuOption;\r
252\r
253 while (!IsListEmpty (&Menu)) {\r
254 MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
255 RemoveEntryList (&MenuOption->Link);\r
256\r
257 //\r
258 // We allocated space for this description when we did a GetToken, free it here\r
259 //\r
260 if (MenuOption->Skip != 0) {\r
261 //\r
262 // For date/time, MenuOption->Description is shared by three Menu Options\r
263 // Data format : [01/02/2004] [11:22:33]\r
264 // Line number : 0 0 1 0 0 1\r
265 //\r
f4113e1f 266 FreePool (MenuOption->Description);\r
7936fb6a 267 }\r
f4113e1f 268 FreePool (MenuOption);\r
7936fb6a 269 }\r
270}\r
271\r
272\r
273/**\r
274 Free Menu option linked list.\r
275\r
276**/\r
277VOID\r
278UiFreeRefreshList (\r
279 VOID\r
280 )\r
281{\r
282 MENU_REFRESH_ENTRY *OldMenuRefreshEntry;\r
283\r
284 while (gMenuRefreshHead != NULL) {\r
285 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
f4113e1f 286 FreePool (gMenuRefreshHead);\r
7936fb6a 287 gMenuRefreshHead = OldMenuRefreshEntry;\r
288 }\r
289\r
290 gMenuRefreshHead = NULL;\r
291}\r
292\r
293\r
294\r
295/**\r
296 Refresh screen.\r
297\r
298**/\r
8d00a0f1 299EFI_STATUS\r
7936fb6a 300RefreshForm (\r
301 VOID\r
302 )\r
303{\r
8d00a0f1 304 CHAR16 *OptionString;\r
305 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
306 UINTN Index;\r
307 EFI_STATUS Status;\r
308 UI_MENU_SELECTION *Selection;\r
309 FORM_BROWSER_STATEMENT *Question;\r
310 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
311 EFI_HII_VALUE *HiiValue;\r
312 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
7936fb6a 313\r
314 if (gMenuRefreshHead != NULL) {\r
315\r
316 MenuRefreshEntry = gMenuRefreshHead;\r
317\r
8d00a0f1 318 //\r
319 // Reset FormPackage update flag\r
320 //\r
321 mHiiPackageListUpdated = FALSE;\r
322\r
7936fb6a 323 do {\r
324 gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
325\r
326 Selection = MenuRefreshEntry->Selection;\r
327 Question = MenuRefreshEntry->MenuOption->ThisTag;\r
328\r
8d00a0f1 329 Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
330 if (EFI_ERROR (Status)) {\r
331 return Status;\r
332 }\r
333\r
334 OptionString = NULL;\r
335 ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
336\r
337 if (OptionString != NULL) {\r
338 //\r
339 // If leading spaces on OptionString - remove the spaces\r
340 //\r
341 for (Index = 0; OptionString[Index] == L' '; Index++)\r
342 ;\r
343\r
344 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
f4113e1f 345 FreePool (OptionString);\r
8d00a0f1 346 }\r
347\r
7936fb6a 348 //\r
8d00a0f1 349 // Question value may be changed, need invoke its Callback()\r
7936fb6a 350 //\r
8d00a0f1 351 ConfigAccess = Selection->FormSet->ConfigAccess;\r
7064c0a5 352 if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
8d00a0f1 353 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
7936fb6a 354\r
8d00a0f1 355 HiiValue = &Question->HiiValue;\r
356 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
357 //\r
358 // Create String in HII database for Configuration Driver to retrieve\r
359 //\r
360 HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, Selection->FormSet->HiiHandle);\r
7936fb6a 361 }\r
362\r
8d00a0f1 363 Status = ConfigAccess->Callback (\r
364 ConfigAccess,\r
365 EFI_BROWSER_ACTION_CHANGING,\r
366 Question->QuestionId,\r
367 HiiValue->Type,\r
368 &HiiValue->Value,\r
369 &ActionRequest\r
370 );\r
7936fb6a 371\r
8d00a0f1 372 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
7936fb6a 373 //\r
8d00a0f1 374 // Clean the String in HII Database\r
7936fb6a 375 //\r
8d00a0f1 376 DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
377 }\r
7936fb6a 378\r
8d00a0f1 379 if (!EFI_ERROR (Status)) {\r
380 switch (ActionRequest) {\r
381 case EFI_BROWSER_ACTION_REQUEST_RESET:\r
382 gResetRequired = TRUE;\r
383 break;\r
7936fb6a 384\r
8d00a0f1 385 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
386 SubmitForm (Selection->FormSet, Selection->Form);\r
387 break;\r
7936fb6a 388\r
8d00a0f1 389 case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
390 Selection->Action = UI_ACTION_EXIT;\r
391 gNvUpdateRequired = FALSE;\r
392 break;\r
393\r
394 default:\r
395 break;\r
396 }\r
7936fb6a 397 }\r
398 }\r
399\r
400 MenuRefreshEntry = MenuRefreshEntry->Next;\r
401\r
402 } while (MenuRefreshEntry != NULL);\r
8d00a0f1 403\r
404 if (mHiiPackageListUpdated) {\r
405 //\r
406 // Package list is updated, force to reparse IFR binary of target Formset\r
407 //\r
408 mHiiPackageListUpdated = FALSE;\r
409 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
410 return EFI_SUCCESS;\r
411 }\r
7936fb6a 412 }\r
8d00a0f1 413\r
414 return EFI_TIMEOUT;\r
7936fb6a 415}\r
416\r
417\r
418/**\r
419 Wait for a given event to fire, or for an optional timeout to expire.\r
420\r
421 @param Event The event to wait for\r
422 @param Timeout An optional timeout value in 100 ns units.\r
423 @param RefreshInterval Menu refresh interval (in seconds).\r
424\r
425 @retval EFI_SUCCESS Event fired before Timeout expired.\r
426 @retval EFI_TIME_OUT Timout expired before Event fired.\r
427\r
428**/\r
429EFI_STATUS\r
430UiWaitForSingleEvent (\r
431 IN EFI_EVENT Event,\r
432 IN UINT64 Timeout, OPTIONAL\r
433 IN UINT8 RefreshInterval OPTIONAL\r
434 )\r
435{\r
436 EFI_STATUS Status;\r
437 UINTN Index;\r
438 EFI_EVENT TimerEvent;\r
439 EFI_EVENT WaitList[2];\r
440\r
441 if (Timeout != 0) {\r
442 //\r
443 // Create a timer event\r
444 //\r
445 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
446 if (!EFI_ERROR (Status)) {\r
447 //\r
448 // Set the timer event\r
449 //\r
450 gBS->SetTimer (\r
451 TimerEvent,\r
452 TimerRelative,\r
453 Timeout\r
454 );\r
455\r
456 //\r
457 // Wait for the original event or the timer\r
458 //\r
459 WaitList[0] = Event;\r
460 WaitList[1] = TimerEvent;\r
461 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
462 gBS->CloseEvent (TimerEvent);\r
463\r
464 //\r
465 // If the timer expired, change the return to timed out\r
466 //\r
467 if (!EFI_ERROR (Status) && Index == 1) {\r
468 Status = EFI_TIMEOUT;\r
469 }\r
470 }\r
471 } else {\r
472 //\r
473 // Update screen every second\r
474 //\r
475 if (RefreshInterval == 0) {\r
476 Timeout = ONE_SECOND;\r
477 } else {\r
478 Timeout = RefreshInterval * ONE_SECOND;\r
479 }\r
480\r
481 do {\r
482 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
483\r
484 //\r
485 // Set the timer event\r
486 //\r
487 gBS->SetTimer (\r
488 TimerEvent,\r
489 TimerRelative,\r
490 Timeout\r
491 );\r
492\r
493 //\r
494 // Wait for the original event or the timer\r
495 //\r
496 WaitList[0] = Event;\r
497 WaitList[1] = TimerEvent;\r
498 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
499\r
500 //\r
501 // If the timer expired, update anything that needs a refresh and keep waiting\r
502 //\r
503 if (!EFI_ERROR (Status) && Index == 1) {\r
504 Status = EFI_TIMEOUT;\r
505 if (RefreshInterval != 0) {\r
8d00a0f1 506 Status = RefreshForm ();\r
7936fb6a 507 }\r
508 }\r
509\r
510 gBS->CloseEvent (TimerEvent);\r
511 } while (Status == EFI_TIMEOUT);\r
512 }\r
513\r
514 return Status;\r
515}\r
516\r
517\r
518/**\r
519 Add one menu option by specified description and context.\r
520\r
521 @param String String description for this option.\r
522 @param Handle Hii handle for the package list.\r
523 @param Statement Statement of this Menu Option.\r
524 @param NumberOfLines Display lines for this Menu Option.\r
525 @param MenuItemCount The index for this Option in the Menu.\r
526\r
527**/\r
528VOID\r
529UiAddMenuOption (\r
530 IN CHAR16 *String,\r
531 IN EFI_HII_HANDLE Handle,\r
532 IN FORM_BROWSER_STATEMENT *Statement,\r
533 IN UINT16 NumberOfLines,\r
534 IN UINT16 MenuItemCount\r
535 )\r
536{\r
537 UI_MENU_OPTION *MenuOption;\r
538 UINTN Index;\r
539 UINTN Count;\r
540\r
541 Count = 1;\r
542\r
543 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
544 //\r
545 // Add three MenuOptions for Date/Time\r
546 // Data format : [01/02/2004] [11:22:33]\r
547 // Line number : 0 0 1 0 0 1\r
548 //\r
549 NumberOfLines = 0;\r
550 Count = 3;\r
551\r
552 if (Statement->Storage == NULL) {\r
553 //\r
554 // For RTC type of date/time, set default refresh interval to be 1 second\r
555 //\r
556 if (Statement->RefreshInterval == 0) {\r
557 Statement->RefreshInterval = 1;\r
558 }\r
559 }\r
560 }\r
561\r
562 for (Index = 0; Index < Count; Index++) {\r
563 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
564 ASSERT (MenuOption);\r
565\r
566 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
567 MenuOption->Description = String;\r
568 MenuOption->Handle = Handle;\r
569 MenuOption->ThisTag = Statement;\r
570 MenuOption->EntryNumber = MenuItemCount;\r
571\r
572 if (Index == 2) {\r
573 //\r
574 // Override LineNumber for the MenuOption in Date/Time sequence\r
575 //\r
576 MenuOption->Skip = 1;\r
577 } else {\r
578 MenuOption->Skip = NumberOfLines;\r
579 }\r
580 MenuOption->Sequence = Index;\r
581\r
582 if (Statement->GrayOutExpression != NULL) {\r
583 MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
584 }\r
585\r
586 if ((Statement->ValueExpression != NULL) ||\r
587 ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
588 MenuOption->ReadOnly = TRUE;\r
589 }\r
590\r
591 InsertTailList (&Menu, &MenuOption->Link);\r
592 }\r
593}\r
594\r
595\r
596/**\r
597 Routine used to abstract a generic dialog interface and return the selected key or string\r
598\r
599 @param NumberOfLines The number of lines for the dialog box\r
600 @param HotKey Defines whether a single character is parsed\r
601 (TRUE) and returned in KeyValue or a string is\r
602 returned in StringBuffer. Two special characters\r
603 are considered when entering a string, a SCAN_ESC\r
604 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates\r
605 string input and returns\r
606 @param MaximumStringSize The maximum size in bytes of a typed in string\r
607 (each character is a CHAR16) and the minimum\r
608 string returned is two bytes\r
609 @param StringBuffer The passed in pointer to the buffer which will\r
610 hold the typed in string if HotKey is FALSE\r
611 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
7936fb6a 612 @param ... A series of (quantity == NumberOfLines) text\r
613 strings which will be used to construct the dialog\r
614 box\r
615\r
616 @retval EFI_SUCCESS Displayed dialog and received user interaction\r
617 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.\r
618 (StringBuffer == NULL) && (HotKey == FALSE))\r
619 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine\r
620\r
621**/\r
622EFI_STATUS\r
623CreateDialog (\r
624 IN UINTN NumberOfLines,\r
625 IN BOOLEAN HotKey,\r
626 IN UINTN MaximumStringSize,\r
627 OUT CHAR16 *StringBuffer,\r
628 OUT EFI_INPUT_KEY *KeyValue,\r
7936fb6a 629 ...\r
630 )\r
631{\r
632 VA_LIST Marker;\r
633 UINTN Count;\r
634 EFI_INPUT_KEY Key;\r
635 UINTN LargestString;\r
636 CHAR16 *TempString;\r
637 CHAR16 *BufferedString;\r
638 CHAR16 *StackString;\r
639 CHAR16 KeyPad[2];\r
640 UINTN Start;\r
641 UINTN Top;\r
642 UINTN Index;\r
643 EFI_STATUS Status;\r
644 BOOLEAN SelectionComplete;\r
645 UINTN InputOffset;\r
646 UINTN CurrentAttribute;\r
647 UINTN DimensionsWidth;\r
648 UINTN DimensionsHeight;\r
649\r
650 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
651 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
652\r
653 SelectionComplete = FALSE;\r
654 InputOffset = 0;\r
655 TempString = AllocateZeroPool (MaximumStringSize * 2);\r
656 BufferedString = AllocateZeroPool (MaximumStringSize * 2);\r
657 CurrentAttribute = gST->ConOut->Mode->Attribute;\r
658\r
659 ASSERT (TempString);\r
660 ASSERT (BufferedString);\r
661\r
f4bcc90f 662 VA_START (Marker, KeyValue);\r
7936fb6a 663\r
664 //\r
665 // Zero the outgoing buffer\r
666 //\r
667 ZeroMem (StringBuffer, MaximumStringSize);\r
668\r
669 if (HotKey) {\r
670 if (KeyValue == NULL) {\r
671 return EFI_INVALID_PARAMETER;\r
672 }\r
673 } else {\r
674 if (StringBuffer == NULL) {\r
675 return EFI_INVALID_PARAMETER;\r
676 }\r
677 }\r
678 //\r
679 // Disable cursor\r
680 //\r
681 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
682\r
f4bcc90f 683 LargestString = 0;\r
7936fb6a 684\r
7936fb6a 685 //\r
686 // Determine the largest string in the dialog box\r
687 // Notice we are starting with 1 since String is the first string\r
688 //\r
f4bcc90f 689 for (Count = 0; Count < NumberOfLines; Count++) {\r
7936fb6a 690 StackString = VA_ARG (Marker, CHAR16 *);\r
691\r
692 if (StackString[0] == L' ') {\r
693 InputOffset = Count + 1;\r
694 }\r
695\r
696 if ((GetStringWidth (StackString) / 2) > LargestString) {\r
697 //\r
698 // Size of the string visually and subtract the width by one for the null-terminator\r
699 //\r
700 LargestString = (GetStringWidth (StackString) / 2);\r
701 }\r
702 }\r
1c9a7554 703 VA_END (Marker);\r
7936fb6a 704\r
705 Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
706 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
707\r
708 Count = 0;\r
709\r
710 //\r
711 // Display the Popup\r
712 //\r
1c9a7554 713 VA_START (Marker, KeyValue);\r
714 CreateSharedPopUp (LargestString, NumberOfLines, Marker);\r
715 VA_END (Marker);\r
7936fb6a 716\r
717 //\r
718 // Take the first key typed and report it back?\r
719 //\r
720 if (HotKey) {\r
721 Status = WaitForKeyStroke (&Key);\r
722 ASSERT_EFI_ERROR (Status);\r
723 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
724\r
725 } else {\r
726 do {\r
727 Status = WaitForKeyStroke (&Key);\r
728\r
729 switch (Key.UnicodeChar) {\r
730 case CHAR_NULL:\r
731 switch (Key.ScanCode) {\r
732 case SCAN_ESC:\r
f4113e1f 733 FreePool (TempString);\r
734 FreePool (BufferedString);\r
7936fb6a 735 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
736 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
737 return EFI_DEVICE_ERROR;\r
738\r
739 default:\r
740 break;\r
741 }\r
742\r
743 break;\r
744\r
745 case CHAR_CARRIAGE_RETURN:\r
746 SelectionComplete = TRUE;\r
f4113e1f 747 FreePool (TempString);\r
748 FreePool (BufferedString);\r
7936fb6a 749 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
750 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
751 return EFI_SUCCESS;\r
752 break;\r
753\r
754 case CHAR_BACKSPACE:\r
755 if (StringBuffer[0] != CHAR_NULL) {\r
756 for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
757 TempString[Index] = StringBuffer[Index];\r
758 }\r
759 //\r
760 // Effectively truncate string by 1 character\r
761 //\r
762 TempString[Index - 1] = CHAR_NULL;\r
763 StrCpy (StringBuffer, TempString);\r
764 }\r
765\r
766 default:\r
767 //\r
768 // If it is the beginning of the string, don't worry about checking maximum limits\r
769 //\r
770 if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
771 StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
772 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
773 } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
774 KeyPad[0] = Key.UnicodeChar;\r
775 KeyPad[1] = CHAR_NULL;\r
776 StrCat (StringBuffer, KeyPad);\r
777 StrCat (TempString, KeyPad);\r
778 }\r
779 //\r
780 // If the width of the input string is now larger than the screen, we nee to\r
781 // adjust the index to start printing portions of the string\r
782 //\r
783 SetUnicodeMem (BufferedString, LargestString, L' ');\r
784\r
785 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
786\r
787 if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
788 Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
789 } else {\r
790 Index = 0;\r
791 }\r
792\r
793 for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
794 BufferedString[Count] = StringBuffer[Index];\r
795 }\r
796\r
797 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
798 break;\r
799 }\r
800 } while (!SelectionComplete);\r
801 }\r
802\r
803 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
804 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
805 return EFI_SUCCESS;\r
806}\r
807\r
808/**\r
809 Draw a pop up windows based on the dimension, number of lines and\r
810 strings specified.\r
811\r
812 @param RequestedWidth The width of the pop-up.\r
813 @param NumberOfLines The number of lines.\r
f4bcc90f 814 @param Marker The variable argument list for the list of string to be printed.\r
7936fb6a 815\r
816**/\r
817VOID\r
818CreateSharedPopUp (\r
819 IN UINTN RequestedWidth,\r
820 IN UINTN NumberOfLines,\r
f4bcc90f 821 IN VA_LIST Marker\r
7936fb6a 822 )\r
823{\r
824 UINTN Index;\r
825 UINTN Count;\r
826 CHAR16 Character;\r
827 UINTN Start;\r
828 UINTN End;\r
829 UINTN Top;\r
830 UINTN Bottom;\r
831 CHAR16 *String;\r
832 UINTN DimensionsWidth;\r
833 UINTN DimensionsHeight;\r
834\r
835 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
836 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
837\r
7936fb6a 838 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
839\r
840 if ((RequestedWidth + 2) > DimensionsWidth) {\r
841 RequestedWidth = DimensionsWidth - 2;\r
842 }\r
843\r
844 //\r
845 // Subtract the PopUp width from total Columns, allow for one space extra on\r
846 // each end plus a border.\r
847 //\r
848 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
849 End = Start + RequestedWidth + 1;\r
850\r
851 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
852 Bottom = Top + NumberOfLines + 2;\r
853\r
854 Character = BOXDRAW_DOWN_RIGHT;\r
855 PrintCharAt (Start, Top, Character);\r
856 Character = BOXDRAW_HORIZONTAL;\r
857 for (Index = Start; Index + 2 < End; Index++) {\r
858 PrintChar (Character);\r
859 }\r
860\r
861 Character = BOXDRAW_DOWN_LEFT;\r
862 PrintChar (Character);\r
863 Character = BOXDRAW_VERTICAL;\r
f4bcc90f 864\r
865 Count = 0;\r
866 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
867 String = VA_ARG (Marker, CHAR16*);\r
7936fb6a 868\r
869 //\r
870 // This will clear the background of the line - we never know who might have been\r
871 // here before us. This differs from the next clear in that it used the non-reverse\r
872 // video for normal printing.\r
873 //\r
874 if (GetStringWidth (String) / 2 > 1) {\r
875 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
876 }\r
877\r
878 //\r
879 // Passing in a space results in the assumption that this is where typing will occur\r
880 //\r
881 if (String[0] == L' ') {\r
882 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
883 }\r
884\r
885 //\r
886 // Passing in a NULL results in a blank space\r
887 //\r
888 if (String[0] == CHAR_NULL) {\r
889 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
890 }\r
891\r
892 PrintStringAt (\r
893 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
894 Index + 1,\r
895 String\r
896 );\r
897 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
898 PrintCharAt (Start, Index + 1, Character);\r
899 PrintCharAt (End - 1, Index + 1, Character);\r
900 }\r
901\r
902 Character = BOXDRAW_UP_RIGHT;\r
903 PrintCharAt (Start, Bottom - 1, Character);\r
904 Character = BOXDRAW_HORIZONTAL;\r
905 for (Index = Start; Index + 2 < End; Index++) {\r
906 PrintChar (Character);\r
907 }\r
908\r
909 Character = BOXDRAW_UP_LEFT;\r
910 PrintChar (Character);\r
911}\r
912\r
913/**\r
914 Draw a pop up windows based on the dimension, number of lines and\r
915 strings specified.\r
916\r
917 @param RequestedWidth The width of the pop-up.\r
918 @param NumberOfLines The number of lines.\r
7936fb6a 919 @param ... A series of text strings that displayed in the pop-up.\r
920\r
921**/\r
922VOID\r
3ebb9bdb 923CreateMultiStringPopUp (\r
7936fb6a 924 IN UINTN RequestedWidth,\r
925 IN UINTN NumberOfLines,\r
7936fb6a 926 ...\r
927 )\r
928{\r
f4bcc90f 929 VA_LIST Marker;\r
930\r
931 VA_START (Marker, NumberOfLines);\r
932 \r
933 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
934\r
935 VA_END (Marker);\r
7936fb6a 936}\r
937\r
938\r
939/**\r
940 Update status bar on the bottom of menu.\r
941\r
942 @param MessageType The type of message to be shown.\r
943 @param Flags The flags in Question header.\r
944 @param State Set or clear.\r
945\r
946**/\r
947VOID\r
948UpdateStatusBar (\r
949 IN UINTN MessageType,\r
950 IN UINT8 Flags,\r
951 IN BOOLEAN State\r
952 )\r
953{\r
954 UINTN Index;\r
7936fb6a 955 CHAR16 *NvUpdateMessage;\r
956 CHAR16 *InputErrorMessage;\r
957\r
958 NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
959 InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
960\r
961 switch (MessageType) {\r
962 case INPUT_ERROR:\r
963 if (State) {\r
964 gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
965 PrintStringAt (\r
966 gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
967 gScreenDimensions.BottomRow - 1,\r
968 InputErrorMessage\r
969 );\r
19b15d63 970 mInputError = TRUE;\r
7936fb6a 971 } else {\r
972 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
973 for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
974 PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");\r
975 }\r
976\r
19b15d63 977 mInputError = FALSE;\r
7936fb6a 978 }\r
979 break;\r
980\r
981 case NV_UPDATE_REQUIRED:\r
0a1147ed 982 if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 983 if (State) {\r
984 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
985 PrintStringAt (\r
986 gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
987 gScreenDimensions.BottomRow - 1,\r
988 NvUpdateMessage\r
989 );\r
990 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
991\r
992 gNvUpdateRequired = TRUE;\r
993 } else {\r
994 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
995 for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
996 PrintAt (\r
997 (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
998 gScreenDimensions.BottomRow - 1,\r
999 L" "\r
1000 );\r
1001 }\r
1002\r
1003 gNvUpdateRequired = FALSE;\r
1004 }\r
1005 }\r
1006 break;\r
1007\r
1008 case REFRESH_STATUS_BAR:\r
19b15d63 1009 if (mInputError) {\r
7936fb6a 1010 UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
1011 }\r
1012\r
1013 if (gNvUpdateRequired) {\r
1014 UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
1015 }\r
1016 break;\r
1017\r
1018 default:\r
1019 break;\r
1020 }\r
1021\r
f4113e1f 1022 FreePool (InputErrorMessage);\r
1023 FreePool (NvUpdateMessage);\r
7936fb6a 1024 return ;\r
1025}\r
1026\r
1027\r
1028/**\r
1029 Get the supported width for a particular op-code\r
1030\r
1031 @param Statement The FORM_BROWSER_STATEMENT structure passed in.\r
1032 @param Handle The handle in the HII database being used\r
1033\r
1034 @return Returns the number of CHAR16 characters that is support.\r
1035\r
1036**/\r
1037UINT16\r
1038GetWidth (\r
1039 IN FORM_BROWSER_STATEMENT *Statement,\r
1040 IN EFI_HII_HANDLE Handle\r
1041 )\r
1042{\r
1043 CHAR16 *String;\r
1044 UINTN Size;\r
1045 UINT16 Width;\r
1046\r
1047 Size = 0;\r
1048\r
1049 //\r
1050 // See if the second text parameter is really NULL\r
1051 //\r
1052 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1053 String = GetToken (Statement->TextTwo, Handle);\r
1054 Size = StrLen (String);\r
f4113e1f 1055 FreePool (String);\r
7936fb6a 1056 }\r
1057\r
1058 if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1059 (Statement->Operand == EFI_IFR_REF_OP) ||\r
1060 (Statement->Operand == EFI_IFR_PASSWORD_OP) ||\r
1061 (Statement->Operand == EFI_IFR_ACTION_OP) ||\r
1062 (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
1063 //\r
1064 // Allow a wide display if text op-code and no secondary text op-code\r
1065 //\r
1066 ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))\r
1067 ) {\r
1068 Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
1069 } else {\r
1070 Width = (UINT16) gPromptBlockWidth;\r
1071 }\r
1072\r
1073 if (Statement->InSubtitle) {\r
1074 Width -= SUBTITLE_INDENT;\r
1075 }\r
1076\r
1077 return Width;\r
1078}\r
1079\r
7936fb6a 1080/**\r
1081 Will copy LineWidth amount of a string in the OutputString buffer and return the\r
1082 number of CHAR16 characters that were copied into the OutputString buffer.\r
1083\r
1084 @param InputString String description for this option.\r
1085 @param LineWidth Width of the desired string to extract in CHAR16\r
1086 characters\r
1087 @param Index Where in InputString to start the copy process\r
1088 @param OutputString Buffer to copy the string into\r
1089\r
1090 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
1091\r
1092**/\r
1093UINT16\r
1094GetLineByWidth (\r
1095 IN CHAR16 *InputString,\r
1096 IN UINT16 LineWidth,\r
1097 IN OUT UINTN *Index,\r
1098 OUT CHAR16 **OutputString\r
1099 )\r
1100{\r
1101 UINT16 Count;\r
1102 UINT16 Count2;\r
1103\r
1104 if (GetLineByWidthFinished) {\r
1105 GetLineByWidthFinished = FALSE;\r
1106 return (UINT16) 0;\r
1107 }\r
1108\r
1109 Count = LineWidth;\r
1110 Count2 = 0;\r
1111\r
1112 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
1113\r
1114 //\r
1115 // Ensure we have got a valid buffer\r
1116 //\r
1117 if (*OutputString != NULL) {\r
1118\r
1119 //\r
1120 //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.\r
1121 //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
1122 //\r
1123 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
1124 *Index = *Index + 2;\r
1125 }\r
1126\r
1127 //\r
1128 // Fast-forward the string and see if there is a carriage-return in the string\r
1129 //\r
1130 for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
1131 ;\r
1132\r
1133 //\r
1134 // Copy the desired LineWidth of data to the output buffer.\r
1135 // Also make sure that we don't copy more than the string.\r
1136 // Also make sure that if there are linefeeds, we account for them.\r
1137 //\r
1138 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
1139 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
1140 ) {\r
1141 //\r
1142 // Convert to CHAR16 value and show that we are done with this operation\r
1143 //\r
1144 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
1145 if (LineWidth != 0) {\r
1146 GetLineByWidthFinished = TRUE;\r
1147 }\r
1148 } else {\r
1149 if (Count2 == LineWidth) {\r
1150 //\r
1151 // Rewind the string from the maximum size until we see a space to break the line\r
1152 //\r
1153 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
1154 ;\r
1155 if (LineWidth == 0) {\r
1156 LineWidth = Count;\r
1157 }\r
1158 } else {\r
1159 LineWidth = Count2;\r
1160 }\r
1161 }\r
1162\r
1163 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
1164\r
1165 //\r
1166 // If currently pointing to a space, increment the index to the first non-space character\r
1167 //\r
1168 for (;\r
1169 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
1170 (*Index)++\r
1171 )\r
1172 ;\r
1173 *Index = (UINT16) (*Index + LineWidth);\r
1174 return LineWidth;\r
1175 } else {\r
1176 return (UINT16) 0;\r
1177 }\r
1178}\r
1179\r
1180\r
1181/**\r
1182 Update display lines for a Menu Option.\r
1183\r
1184 @param Selection The user's selection.\r
1185 @param MenuOption The MenuOption to be checked.\r
1186 @param OptionalString The option string.\r
1187 @param SkipValue The number of lins to skip.\r
1188\r
7936fb6a 1189**/\r
1190VOID\r
1191UpdateOptionSkipLines (\r
1192 IN UI_MENU_SELECTION *Selection,\r
1193 IN UI_MENU_OPTION *MenuOption,\r
1194 OUT CHAR16 **OptionalString,\r
1195 IN UINTN SkipValue\r
1196 )\r
1197{\r
1198 UINTN Index;\r
1199 UINT16 Width;\r
1200 UINTN Row;\r
1201 UINTN OriginalRow;\r
1202 CHAR16 *OutputString;\r
1203 CHAR16 *OptionString;\r
1204\r
1205 Row = 0;\r
1206 OptionString = *OptionalString;\r
1207 OutputString = NULL;\r
1208\r
1209 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1210\r
1211 if (OptionString != NULL) {\r
1212 Width = (UINT16) gOptionBlockWidth;\r
1213\r
1214 OriginalRow = Row;\r
1215\r
1216 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1217 //\r
1218 // If there is more string to process print on the next row and increment the Skip value\r
1219 //\r
d1a54e2c 1220 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1221 if (SkipValue == 0) {\r
1222 Row++;\r
1223 //\r
1224 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1225 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1226 // some testing to ensure we are keeping this in-sync.\r
1227 //\r
1228 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1229 //\r
1230 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1231 MenuOption->Skip++;\r
1232 }\r
1233 }\r
1234 }\r
1235\r
f4113e1f 1236 FreePool (OutputString);\r
7936fb6a 1237 if (SkipValue != 0) {\r
1238 SkipValue--;\r
1239 }\r
1240 }\r
1241\r
1242 Row = OriginalRow;\r
1243 }\r
1244\r
1245 *OptionalString = OptionString;\r
1246}\r
1247\r
1248\r
1249/**\r
1250 Check whether this Menu Option could be highlighted.\r
1251\r
1252 This is an internal function.\r
1253\r
1254 @param MenuOption The MenuOption to be checked.\r
1255\r
1256 @retval TRUE This Menu Option is selectable.\r
1257 @retval FALSE This Menu Option could not be selected.\r
1258\r
1259**/\r
1260BOOLEAN\r
1261IsSelectable (\r
1262 UI_MENU_OPTION *MenuOption\r
1263 )\r
1264{\r
1265 if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1266 MenuOption->GrayOut || MenuOption->ReadOnly) {\r
1267 return FALSE;\r
1268 } else {\r
1269 return TRUE;\r
1270 }\r
1271}\r
1272\r
1273\r
1274/**\r
1275 Determine if the menu is the last menu that can be selected.\r
1276\r
1277 This is an internal function.\r
1278 \r
1279 @param Direction The scroll direction. False is down. True is up.\r
1280 @param CurrentPos The current focus.\r
1281\r
1282 @return FALSE -- the menu isn't the last menu that can be selected.\r
1283 @return TRUE -- the menu is the last menu that can be selected.\r
1284\r
1285**/\r
1286BOOLEAN\r
1287ValueIsScroll (\r
1288 IN BOOLEAN Direction,\r
1289 IN LIST_ENTRY *CurrentPos\r
1290 )\r
1291{\r
1292 LIST_ENTRY *Temp;\r
1293 UI_MENU_OPTION *MenuOption;\r
1294\r
1295 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
1296\r
1297 if (Temp == &Menu) {\r
1298 return TRUE;\r
1299 }\r
1300\r
1301 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
1302 MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
1303 if (IsSelectable (MenuOption)) {\r
1304 return FALSE;\r
1305 }\r
1306 }\r
1307\r
1308 return TRUE;\r
1309}\r
1310\r
1311\r
1312/**\r
1313 Move to next selectable statement.\r
1314 \r
1315 This is an internal function.\r
1316 \r
1317 @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
1318 @param CurrentPosition Current position.\r
1319\r
1320 @return The row distance from current MenuOption to next selectable MenuOption.\r
1321\r
1322**/\r
1323INTN\r
1324MoveToNextStatement (\r
1325 IN BOOLEAN GoUp,\r
1326 IN OUT LIST_ENTRY **CurrentPosition\r
1327 )\r
1328{\r
1329 INTN Distance;\r
1330 LIST_ENTRY *Pos;\r
1331 BOOLEAN HitEnd;\r
1332 UI_MENU_OPTION *NextMenuOption;\r
1333\r
1334 Distance = 0;\r
1335 Pos = *CurrentPosition;\r
1336 HitEnd = FALSE;\r
1337\r
1338 while (TRUE) {\r
1339 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1340 if (IsSelectable (NextMenuOption)) {\r
1341 break;\r
1342 }\r
1343 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
1344 HitEnd = TRUE;\r
1345 break;\r
1346 }\r
1347 Distance += NextMenuOption->Skip;\r
1348 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1349 }\r
1350\r
1351 if (HitEnd) {\r
1352 //\r
1353 // If we hit end there is still no statement can be focused,\r
1354 // we go backwards to find the statement can be focused.\r
1355 //\r
1356 Distance = 0;\r
1357 Pos = *CurrentPosition;\r
1358\r
1359 while (TRUE) {\r
1360 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1361 if (IsSelectable (NextMenuOption)) {\r
1362 break;\r
1363 }\r
1364 if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
1365 ASSERT (FALSE);\r
1366 break;\r
1367 }\r
1368 Distance -= NextMenuOption->Skip;\r
1369 Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1370 }\r
1371 }\r
1372\r
1373 *CurrentPosition = &NextMenuOption->Link;\r
1374 return Distance;\r
1375}\r
1376\r
1377\r
1378/**\r
1379 Adjust Data and Time position accordingly.\r
1380 Data format : [01/02/2004] [11:22:33]\r
1381 Line number : 0 0 1 0 0 1\r
1382 \r
1383 This is an internal function.\r
1384\r
1385 @param DirectionUp the up or down direction. False is down. True is\r
1386 up.\r
1387 @param CurrentPosition Current position. On return: Point to the last\r
1388 Option (Year or Second) if up; Point to the first\r
1389 Option (Month or Hour) if down.\r
1390\r
1391 @return Return line number to pad. It is possible that we stand on a zero-advance\r
1392 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
1393\r
1394**/\r
1395UINTN\r
1396AdjustDateAndTimePosition (\r
1397 IN BOOLEAN DirectionUp,\r
1398 IN OUT LIST_ENTRY **CurrentPosition\r
1399 )\r
1400{\r
1401 UINTN Count;\r
1402 LIST_ENTRY *NewPosition;\r
1403 UI_MENU_OPTION *MenuOption;\r
1404 UINTN PadLineNumber;\r
1405\r
1406 PadLineNumber = 0;\r
1407 NewPosition = *CurrentPosition;\r
1408 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1409\r
1410 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
1411 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
1412 //\r
1413 // Calculate the distance from current position to the last Date/Time MenuOption\r
1414 //\r
1415 Count = 0;\r
1416 while (MenuOption->Skip == 0) {\r
1417 Count++;\r
1418 NewPosition = NewPosition->ForwardLink;\r
1419 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1420 PadLineNumber = 1;\r
1421 }\r
1422\r
1423 NewPosition = *CurrentPosition;\r
1424 if (DirectionUp) {\r
1425 //\r
1426 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
1427 // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
1428 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
1429 // checking can be done.\r
1430 //\r
1431 while (Count++ < 2) {\r
1432 NewPosition = NewPosition->BackLink;\r
1433 }\r
1434 } else {\r
1435 //\r
1436 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
1437 // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
1438 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
1439 // checking can be done.\r
1440 //\r
1441 while (Count-- > 0) {\r
1442 NewPosition = NewPosition->ForwardLink;\r
1443 }\r
1444 }\r
1445\r
1446 *CurrentPosition = NewPosition;\r
1447 }\r
1448\r
1449 return PadLineNumber;\r
1450}\r
1451\r
cb7d01c0 1452/**\r
1453 Find HII Handle in the HII database associated with given Device Path.\r
1454\r
1455 If DevicePath is NULL, then ASSERT.\r
1456\r
1457 @param DevicePath Device Path associated with the HII package list\r
1458 handle.\r
1459\r
1460 @retval Handle HII package list Handle associated with the Device\r
1461 Path.\r
1462 @retval NULL Hii Package list handle is not found.\r
1463\r
1464**/\r
1465EFI_HII_HANDLE\r
1466EFIAPI\r
1467DevicePathToHiiHandle (\r
1468 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1469 )\r
1470{\r
1471 EFI_STATUS Status;\r
1472 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
1473 UINTN BufferSize;\r
1474 UINTN HandleCount;\r
1475 UINTN Index;\r
1476 EFI_HANDLE Handle;\r
1477 EFI_HANDLE DriverHandle;\r
1478 EFI_HII_HANDLE *HiiHandles;\r
1479 EFI_HII_HANDLE HiiHandle;\r
1480\r
1481 ASSERT (DevicePath != NULL);\r
1482\r
1483 TmpDevicePath = DevicePath;\r
1484 //\r
1485 // Locate Device Path Protocol handle buffer\r
1486 //\r
1487 Status = gBS->LocateDevicePath (\r
1488 &gEfiDevicePathProtocolGuid,\r
1489 &TmpDevicePath,\r
1490 &DriverHandle\r
1491 );\r
1492 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
1493 return NULL;\r
1494 }\r
1495\r
1496 //\r
1497 // Retrieve all HII Handles from HII database\r
1498 //\r
1499 BufferSize = 0x1000;\r
1500 HiiHandles = AllocatePool (BufferSize);\r
1501 ASSERT (HiiHandles != NULL);\r
1502 Status = mHiiDatabase->ListPackageLists (\r
1503 mHiiDatabase,\r
1504 EFI_HII_PACKAGE_TYPE_ALL,\r
1505 NULL,\r
1506 &BufferSize,\r
1507 HiiHandles\r
1508 );\r
1509 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1510 FreePool (HiiHandles);\r
1511 HiiHandles = AllocatePool (BufferSize);\r
1512 ASSERT (HiiHandles != NULL);\r
1513\r
1514 Status = mHiiDatabase->ListPackageLists (\r
1515 mHiiDatabase,\r
1516 EFI_HII_PACKAGE_TYPE_ALL,\r
1517 NULL,\r
1518 &BufferSize,\r
1519 HiiHandles\r
1520 );\r
1521 }\r
1522\r
1523 if (EFI_ERROR (Status)) {\r
1524 FreePool (HiiHandles);\r
1525 return NULL;\r
1526 }\r
1527\r
1528 //\r
1529 // Search Hii Handle by Driver Handle\r
1530 //\r
1531 HiiHandle = NULL;\r
1532 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
1533 for (Index = 0; Index < HandleCount; Index++) {\r
1534 Status = mHiiDatabase->GetPackageListHandle (\r
1535 mHiiDatabase,\r
1536 HiiHandles[Index],\r
1537 &Handle\r
1538 );\r
1539 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
1540 HiiHandle = HiiHandles[Index];\r
1541 break;\r
1542 }\r
1543 }\r
1544\r
1545 FreePool (HiiHandles);\r
1546 return HiiHandle;\r
1547}\r
7936fb6a 1548\r
1549/**\r
1550 Display menu and wait for user to select one menu option, then return it.\r
1551 If AutoBoot is enabled, then if user doesn't select any option,\r
1552 after period of time, it will automatically return the first menu option.\r
1553\r
1554 @param Selection Menu selection.\r
1555\r
1556 @retval EFI_SUCESSS This function always return successfully for now.\r
1557\r
1558**/\r
1559EFI_STATUS\r
1560UiDisplayMenu (\r
1561 IN OUT UI_MENU_SELECTION *Selection\r
1562 )\r
1563{\r
1564 INTN SkipValue;\r
1565 INTN Difference;\r
1566 INTN OldSkipValue;\r
1567 UINTN DistanceValue;\r
1568 UINTN Row;\r
1569 UINTN Col;\r
1570 UINTN Temp;\r
1571 UINTN Temp2;\r
1572 UINTN TopRow;\r
1573 UINTN BottomRow;\r
1574 UINTN OriginalRow;\r
1575 UINTN Index;\r
1576 UINT32 Count;\r
1577 UINT16 Width;\r
1578 CHAR16 *StringPtr;\r
1579 CHAR16 *OptionString;\r
1580 CHAR16 *OutputString;\r
1581 CHAR16 *FormattedString;\r
1582 CHAR16 YesResponse;\r
1583 CHAR16 NoResponse;\r
1584 BOOLEAN NewLine;\r
1585 BOOLEAN Repaint;\r
1586 BOOLEAN SavedValue;\r
1587 EFI_STATUS Status;\r
1588 EFI_INPUT_KEY Key;\r
1589 LIST_ENTRY *Link;\r
1590 LIST_ENTRY *NewPos;\r
1591 LIST_ENTRY *TopOfScreen;\r
1592 LIST_ENTRY *SavedListEntry;\r
1593 UI_MENU_OPTION *MenuOption;\r
1594 UI_MENU_OPTION *NextMenuOption;\r
1595 UI_MENU_OPTION *SavedMenuOption;\r
1596 UI_MENU_OPTION *PreviousMenuOption;\r
1597 UI_CONTROL_FLAG ControlFlag;\r
1598 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
1599 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
1600 UI_SCREEN_OPERATION ScreenOperation;\r
1601 UINT8 MinRefreshInterval;\r
1602 UINTN BufferSize;\r
1603 UINT16 DefaultId;\r
1604 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1605 FORM_BROWSER_STATEMENT *Statement;\r
63d55bb9
LG
1606 CHAR16 TemStr[2];\r
1607 UINT8 *DevicePathBuffer;\r
1608 UINT8 DigitUint8;\r
7936fb6a 1609\r
1610 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1611\r
1612 Status = EFI_SUCCESS;\r
1613 FormattedString = NULL;\r
1614 OptionString = NULL;\r
1615 ScreenOperation = UiNoOperation;\r
1616 NewLine = TRUE;\r
1617 MinRefreshInterval = 0;\r
1618 DefaultId = 0;\r
1619\r
1620 OutputString = NULL;\r
1621 gUpArrow = FALSE;\r
1622 gDownArrow = FALSE;\r
1623 SkipValue = 0;\r
1624 OldSkipValue = 0;\r
1625 MenuRefreshEntry = gMenuRefreshHead;\r
1626\r
1627 NextMenuOption = NULL;\r
1628 PreviousMenuOption = NULL;\r
1629 SavedMenuOption = NULL;\r
1630\r
1631 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1632\r
0a1147ed 1633 if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 1634 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1635 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1636 } else {\r
1637 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1638 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1639 }\r
1640\r
1641 Col = LocalScreen.LeftColumn;\r
1642 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1643\r
1644 Selection->TopRow = TopRow;\r
1645 Selection->BottomRow = BottomRow;\r
1646 Selection->PromptCol = Col;\r
1647 Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1648 Selection->Statement = NULL;\r
1649\r
1650 TopOfScreen = Menu.ForwardLink;\r
1651 Repaint = TRUE;\r
1652 MenuOption = NULL;\r
1653\r
1654 //\r
1655 // Get user's selection\r
1656 //\r
1657 NewPos = Menu.ForwardLink;\r
1658\r
1659 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1660 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1661\r
1662 ControlFlag = CfInitialization;\r
1663 Selection->Action = UI_ACTION_NONE;\r
1664 while (TRUE) {\r
1665 switch (ControlFlag) {\r
1666 case CfInitialization:\r
1667 if (IsListEmpty (&Menu)) {\r
1668 ControlFlag = CfReadKey;\r
1669 } else {\r
1670 ControlFlag = CfCheckSelection;\r
1671 }\r
1672 break;\r
1673\r
1674 case CfCheckSelection:\r
1675 if (Selection->Action != UI_ACTION_NONE) {\r
1676 ControlFlag = CfExit;\r
1677 } else {\r
1678 ControlFlag = CfRepaint;\r
1679 }\r
1680 break;\r
1681\r
1682 case CfRepaint:\r
1683 ControlFlag = CfRefreshHighLight;\r
1684\r
1685 if (Repaint) {\r
1686 //\r
1687 // Display menu\r
1688 //\r
1689 gDownArrow = FALSE;\r
1690 gUpArrow = FALSE;\r
1691 Row = TopRow;\r
1692\r
1693 Temp = SkipValue;\r
1694 Temp2 = SkipValue;\r
1695\r
1696 ClearLines (\r
1697 LocalScreen.LeftColumn,\r
1698 LocalScreen.RightColumn,\r
1699 TopRow - SCROLL_ARROW_HEIGHT,\r
1700 BottomRow + SCROLL_ARROW_HEIGHT,\r
1701 FIELD_TEXT | FIELD_BACKGROUND\r
1702 );\r
1703\r
1704 UiFreeRefreshList ();\r
1705 MinRefreshInterval = 0;\r
1706\r
1707 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
1708 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
1709 MenuOption->Row = Row;\r
1710 MenuOption->Col = Col;\r
1711 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1712\r
1713 Statement = MenuOption->ThisTag;\r
1714 if (Statement->InSubtitle) {\r
1715 MenuOption->Col += SUBTITLE_INDENT;\r
1716 }\r
1717\r
1718 if (MenuOption->GrayOut) {\r
1719 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1720 } else {\r
1721 if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
1722 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1723 }\r
1724 }\r
1725\r
1726 Width = GetWidth (Statement, MenuOption->Handle);\r
1727 OriginalRow = Row;\r
1728\r
1729 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1730 if ((Temp == 0) && (Row <= BottomRow)) {\r
1731 PrintStringAt (MenuOption->Col, Row, OutputString);\r
1732 }\r
1733 //\r
1734 // If there is more string to process print on the next row and increment the Skip value\r
1735 //\r
d1a54e2c 1736 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 1737 if (Temp == 0) {\r
1738 Row++;\r
1739 }\r
1740 }\r
1741\r
f4113e1f 1742 FreePool (OutputString);\r
7936fb6a 1743 if (Temp != 0) {\r
1744 Temp--;\r
1745 }\r
1746 }\r
1747\r
1748 Temp = 0;\r
1749 Row = OriginalRow;\r
1750\r
1751 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
8d00a0f1 1752 Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1753 if (EFI_ERROR (Status)) {\r
1754 //\r
1755 // Repaint to clear possible error prompt pop-up\r
1756 //\r
1757 Repaint = TRUE;\r
1758 NewLine = TRUE;\r
1759 ControlFlag = CfRepaint;\r
1760 break;\r
1761 }\r
7936fb6a 1762\r
1763 if (OptionString != NULL) {\r
1764 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
1765 //\r
1766 // If leading spaces on OptionString - remove the spaces\r
1767 //\r
1768 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1769 MenuOption->OptCol++;\r
1770 }\r
1771\r
1772 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1773 OptionString[Count] = OptionString[Index];\r
1774 Count++;\r
1775 }\r
1776\r
1777 OptionString[Count] = CHAR_NULL;\r
1778 }\r
1779\r
1780 //\r
1781 // If Question request refresh, register the op-code\r
1782 //\r
1783 if (Statement->RefreshInterval != 0) {\r
1784 //\r
1785 // Menu will be refreshed at minimal interval of all Questions\r
1786 // which have refresh request\r
1787 //\r
1788 if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
1789 MinRefreshInterval = Statement->RefreshInterval;\r
1790 }\r
1791\r
1792 if (gMenuRefreshHead == NULL) {\r
1793 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1794 ASSERT (MenuRefreshEntry != NULL);\r
1795 MenuRefreshEntry->MenuOption = MenuOption;\r
1796 MenuRefreshEntry->Selection = Selection;\r
1797 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1798 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1799 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1800 gMenuRefreshHead = MenuRefreshEntry;\r
1801 } else {\r
1802 //\r
1803 // Advance to the last entry\r
1804 //\r
1805 for (MenuRefreshEntry = gMenuRefreshHead;\r
1806 MenuRefreshEntry->Next != NULL;\r
1807 MenuRefreshEntry = MenuRefreshEntry->Next\r
1808 )\r
1809 ;\r
1810 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1811 ASSERT (MenuRefreshEntry->Next != NULL);\r
1812 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1813 MenuRefreshEntry->MenuOption = MenuOption;\r
1814 MenuRefreshEntry->Selection = Selection;\r
1815 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1816 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1817 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1818 }\r
1819 }\r
1820\r
1821 Width = (UINT16) gOptionBlockWidth;\r
1822 OriginalRow = Row;\r
1823\r
1824 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1825 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1826 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1827 }\r
1828 //\r
1829 // If there is more string to process print on the next row and increment the Skip value\r
1830 //\r
d1a54e2c 1831 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1832 if (Temp2 == 0) {\r
1833 Row++;\r
1834 //\r
1835 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1836 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1837 // some testing to ensure we are keeping this in-sync.\r
1838 //\r
1839 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1840 //\r
1841 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1842 MenuOption->Skip++;\r
1843 }\r
1844 }\r
1845 }\r
1846\r
f4113e1f 1847 FreePool (OutputString);\r
7936fb6a 1848 if (Temp2 != 0) {\r
1849 Temp2--;\r
1850 }\r
1851 }\r
1852\r
1853 Temp2 = 0;\r
1854 Row = OriginalRow;\r
1855\r
f4113e1f 1856 FreePool (OptionString);\r
7936fb6a 1857 }\r
1858 //\r
1859 // If this is a text op with secondary text information\r
1860 //\r
1861 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1862 StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
1863\r
1864 Width = (UINT16) gOptionBlockWidth;\r
1865 OriginalRow = Row;\r
1866\r
1867 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1868 if ((Temp == 0) && (Row <= BottomRow)) {\r
1869 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1870 }\r
1871 //\r
1872 // If there is more string to process print on the next row and increment the Skip value\r
1873 //\r
d1a54e2c 1874 if (StrLen (&StringPtr[Index]) != 0) {\r
7936fb6a 1875 if (Temp2 == 0) {\r
1876 Row++;\r
1877 //\r
1878 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1879 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1880 // some testing to ensure we are keeping this in-sync.\r
1881 //\r
1882 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1883 //\r
1884 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1885 MenuOption->Skip++;\r
1886 }\r
1887 }\r
1888 }\r
1889\r
f4113e1f 1890 FreePool (OutputString);\r
7936fb6a 1891 if (Temp2 != 0) {\r
1892 Temp2--;\r
1893 }\r
1894 }\r
1895\r
1896 Row = OriginalRow;\r
f4113e1f 1897 FreePool (StringPtr);\r
7936fb6a 1898 }\r
1899\r
1900 //\r
1901 // Need to handle the bottom of the display\r
1902 //\r
1903 if (MenuOption->Skip > 1) {\r
1904 Row += MenuOption->Skip - SkipValue;\r
1905 SkipValue = 0;\r
1906 } else {\r
1907 Row += MenuOption->Skip;\r
1908 }\r
1909\r
1910 if (Row > BottomRow) {\r
1911 if (!ValueIsScroll (FALSE, Link)) {\r
1912 gDownArrow = TRUE;\r
1913 }\r
1914\r
1915 Row = BottomRow + 1;\r
1916 break;\r
1917 }\r
1918 }\r
1919\r
1920 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
1921 gUpArrow = TRUE;\r
1922 }\r
1923\r
1924 if (gUpArrow) {\r
1925 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1926 PrintAt (\r
1927 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1928 TopRow - SCROLL_ARROW_HEIGHT,\r
1929 L"%c",\r
1930 ARROW_UP\r
1931 );\r
1932 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1933 }\r
1934\r
1935 if (gDownArrow) {\r
1936 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1937 PrintAt (\r
1938 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1939 BottomRow + SCROLL_ARROW_HEIGHT,\r
1940 L"%c",\r
1941 ARROW_DOWN\r
1942 );\r
1943 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1944 }\r
1945\r
1946 MenuOption = NULL;\r
1947 }\r
1948 break;\r
1949\r
1950 case CfRefreshHighLight:\r
1951 //\r
1952 // MenuOption: Last menu option that need to remove hilight\r
1953 // MenuOption is set to NULL in Repaint\r
1954 // NewPos: Current menu option that need to hilight\r
1955 //\r
1956 ControlFlag = CfUpdateHelpString;\r
1957\r
1958 //\r
1959 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
1960 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
1961 //\r
1962 SavedValue = Repaint;\r
1963 Repaint = FALSE;\r
1964\r
1965 if (Selection->QuestionId != 0) {\r
1966 NewPos = Menu.ForwardLink;\r
1967 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1968\r
1969 while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {\r
1970 NewPos = NewPos->ForwardLink;\r
1971 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
1972 }\r
1973 if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
1974 //\r
1975 // Target Question found, find its MenuOption\r
1976 //\r
1977 Link = TopOfScreen;\r
1978\r
1979 for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
1980 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
1981 Index += SavedMenuOption->Skip;\r
1982 Link = Link->ForwardLink;\r
1983 }\r
1984\r
1985 if (Link != NewPos || Index > BottomRow) {\r
1986 //\r
1987 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
1988 //\r
1989 Link = NewPos;\r
1990 for (Index = TopRow; Index <= BottomRow; ) {\r
1991 Link = Link->BackLink;\r
1992 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
1993 Index += SavedMenuOption->Skip;\r
1994 }\r
1995 TopOfScreen = Link->ForwardLink;\r
1996\r
1997 Repaint = TRUE;\r
1998 NewLine = TRUE;\r
1999 ControlFlag = CfRepaint;\r
2000 break;\r
2001 }\r
2002 } else {\r
2003 //\r
2004 // Target Question not found, highlight the default menu option\r
2005 //\r
2006 NewPos = TopOfScreen;\r
2007 }\r
2008\r
2009 Selection->QuestionId = 0;\r
2010 }\r
2011\r
2012 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2013 if (MenuOption != NULL) {\r
2014 //\r
2015 // Remove highlight on last Menu Option\r
2016 //\r
2017 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2018 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2019 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2020 if (OptionString != NULL) {\r
2021 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2022 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2023 ) {\r
2024 //\r
2025 // If leading spaces on OptionString - remove the spaces\r
2026 //\r
2027 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2028 ;\r
2029\r
2030 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2031 OptionString[Count] = OptionString[Index];\r
2032 Count++;\r
2033 }\r
2034\r
2035 OptionString[Count] = CHAR_NULL;\r
2036 }\r
2037\r
2038 Width = (UINT16) gOptionBlockWidth;\r
2039 OriginalRow = MenuOption->Row;\r
2040\r
2041 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2042 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2043 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2044 }\r
2045 //\r
2046 // If there is more string to process print on the next row and increment the Skip value\r
2047 //\r
d1a54e2c 2048 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2049 MenuOption->Row++;\r
2050 }\r
2051\r
f4113e1f 2052 FreePool (OutputString);\r
7936fb6a 2053 }\r
2054\r
2055 MenuOption->Row = OriginalRow;\r
2056\r
f4113e1f 2057 FreePool (OptionString);\r
7936fb6a 2058 } else {\r
2059 if (NewLine) {\r
2060 if (MenuOption->GrayOut) {\r
2061 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2062 } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
2063 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
2064 }\r
2065\r
2066 OriginalRow = MenuOption->Row;\r
2067 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
2068\r
2069 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2070 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2071 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2072 }\r
2073 //\r
2074 // If there is more string to process print on the next row and increment the Skip value\r
2075 //\r
d1a54e2c 2076 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2077 MenuOption->Row++;\r
2078 }\r
2079\r
f4113e1f 2080 FreePool (OutputString);\r
7936fb6a 2081 }\r
2082\r
2083 MenuOption->Row = OriginalRow;\r
2084 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2085 }\r
2086 }\r
2087 }\r
2088\r
2089 //\r
2090 // This is only possible if we entered this page and the first menu option is\r
2091 // a "non-menu" item. In that case, force it UiDown\r
2092 //\r
2093 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2094 if (!IsSelectable (MenuOption)) {\r
2095 ASSERT (ScreenOperation == UiNoOperation);\r
2096 ScreenOperation = UiDown;\r
2097 ControlFlag = CfScreenOperation;\r
2098 break;\r
2099 }\r
2100\r
2101 //\r
2102 // This is the current selected statement\r
2103 //\r
2104 Statement = MenuOption->ThisTag;\r
2105 Selection->Statement = Statement;\r
2106\r
2107 //\r
2108 // Set reverse attribute\r
2109 //\r
2110 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
2111 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2112\r
2113 //\r
2114 // Assuming that we have a refresh linked-list created, lets annotate the\r
2115 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
2116 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
2117 //\r
2118 if (gMenuRefreshHead != NULL) {\r
2119 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
2120 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
2121 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
2122 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
2123 }\r
2124 }\r
2125 }\r
2126\r
2127 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2128 if (OptionString != NULL) {\r
2129 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
2130 //\r
2131 // If leading spaces on OptionString - remove the spaces\r
2132 //\r
2133 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2134 ;\r
2135\r
2136 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2137 OptionString[Count] = OptionString[Index];\r
2138 Count++;\r
2139 }\r
2140\r
2141 OptionString[Count] = CHAR_NULL;\r
2142 }\r
2143 Width = (UINT16) gOptionBlockWidth;\r
2144\r
2145 OriginalRow = MenuOption->Row;\r
2146\r
2147 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2148 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2149 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2150 }\r
2151 //\r
2152 // If there is more string to process print on the next row and increment the Skip value\r
2153 //\r
d1a54e2c 2154 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2155 MenuOption->Row++;\r
2156 }\r
2157\r
f4113e1f 2158 FreePool (OutputString);\r
7936fb6a 2159 }\r
2160\r
2161 MenuOption->Row = OriginalRow;\r
2162\r
f4113e1f 2163 FreePool (OptionString);\r
7936fb6a 2164 } else {\r
2165 if (NewLine) {\r
2166 OriginalRow = MenuOption->Row;\r
2167\r
2168 Width = GetWidth (Statement, MenuOption->Handle);\r
2169\r
2170 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2171 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2172 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2173 }\r
2174 //\r
2175 // If there is more string to process print on the next row and increment the Skip value\r
2176 //\r
d1a54e2c 2177 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2178 MenuOption->Row++;\r
2179 }\r
2180\r
f4113e1f 2181 FreePool (OutputString);\r
7936fb6a 2182 }\r
2183\r
2184 MenuOption->Row = OriginalRow;\r
2185\r
2186 }\r
2187 }\r
2188\r
8d00a0f1 2189 UpdateKeyHelp (MenuOption, FALSE);\r
2190\r
7936fb6a 2191 //\r
2192 // Clear reverse attribute\r
2193 //\r
2194 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2195 }\r
2196 //\r
2197 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2198 // if we didn't break halfway when process CfRefreshHighLight.\r
2199 //\r
2200 Repaint = SavedValue;\r
2201 break;\r
2202\r
2203 case CfUpdateHelpString:\r
2204 ControlFlag = CfPrepareToReadKey;\r
2205\r
0a1147ed 2206 if (Repaint || NewLine) {\r
7936fb6a 2207 //\r
2208 // Don't print anything if it is a NULL help token\r
2209 //\r
2210 if (MenuOption->ThisTag->Help == 0) {\r
2211 StringPtr = L"\0";\r
2212 } else {\r
2213 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2214 }\r
2215\r
2216 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2217\r
2218 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2219\r
2220 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2221 //\r
2222 // Pad String with spaces to simulate a clearing of the previous line\r
2223 //\r
2224 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
2225 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
2226 }\r
2227\r
2228 PrintStringAt (\r
2229 LocalScreen.RightColumn - gHelpBlockWidth,\r
2230 Index + TopRow,\r
2231 &FormattedString[Index * gHelpBlockWidth * 2]\r
2232 );\r
2233 }\r
2234 }\r
2235 //\r
2236 // Reset this flag every time we finish using it.\r
2237 //\r
2238 Repaint = FALSE;\r
2239 NewLine = FALSE;\r
2240 break;\r
2241\r
2242 case CfPrepareToReadKey:\r
2243 ControlFlag = CfReadKey;\r
2244 ScreenOperation = UiNoOperation;\r
2245 break;\r
2246\r
2247 case CfReadKey:\r
2248 ControlFlag = CfScreenOperation;\r
2249\r
2250 //\r
2251 // Wait for user's selection\r
2252 //\r
2253 do {\r
2254 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
2255 } while (Status == EFI_TIMEOUT);\r
2256\r
8d00a0f1 2257 if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
7936fb6a 2258 //\r
8d00a0f1 2259 // IFR is updated in Callback of refresh opcode, re-parse it\r
7936fb6a 2260 //\r
8d00a0f1 2261 ControlFlag = CfUiReset;\r
2262 Selection->Statement = NULL;\r
2263 break;\r
2264 }\r
2265\r
2266 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2267 //\r
2268 // if we encounter error, continue to read another key in.\r
2269 //\r
2270 if (EFI_ERROR (Status)) {\r
2271 ControlFlag = CfReadKey;\r
2272 break;\r
7936fb6a 2273 }\r
2274\r
2275 if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {\r
2276 //\r
2277 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
2278 //\r
2279 break;\r
2280 }\r
2281\r
2282 switch (Key.UnicodeChar) {\r
2283 case CHAR_CARRIAGE_RETURN:\r
2284 ScreenOperation = UiSelect;\r
2285 gDirection = 0;\r
2286 break;\r
2287\r
2288 //\r
2289 // We will push the adjustment of these numeric values directly to the input handler\r
2290 // NOTE: we won't handle manual input numeric\r
2291 //\r
2292 case '+':\r
2293 case '-':\r
2294 Statement = MenuOption->ThisTag;\r
2295 if ((Statement->Operand == EFI_IFR_DATE_OP)\r
2296 || (Statement->Operand == EFI_IFR_TIME_OP)\r
2297 || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
2298 ){\r
2299 if (Key.UnicodeChar == '+') {\r
2300 gDirection = SCAN_RIGHT;\r
2301 } else {\r
2302 gDirection = SCAN_LEFT;\r
2303 }\r
2304 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
8d00a0f1 2305 if (EFI_ERROR (Status)) {\r
2306 //\r
2307 // Repaint to clear possible error prompt pop-up\r
2308 //\r
2309 Repaint = TRUE;\r
2310 NewLine = TRUE;\r
2311 }\r
676df92c 2312 if (OptionString != NULL) {\r
2313 FreePool (OptionString);\r
2314 }\r
7936fb6a 2315 }\r
2316 break;\r
2317\r
2318 case '^':\r
2319 ScreenOperation = UiUp;\r
2320 break;\r
2321\r
2322 case 'V':\r
2323 case 'v':\r
2324 ScreenOperation = UiDown;\r
2325 break;\r
2326\r
2327 case ' ':\r
0a1147ed 2328 if (gClassOfVfr != FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 2329 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
2330 ScreenOperation = UiSelect;\r
2331 }\r
2332 }\r
2333 break;\r
2334\r
2335 case CHAR_NULL:\r
2336 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
2337 ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
2338 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
2339 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2340 ) {\r
2341 //\r
2342 // If the function key has been disabled, just ignore the key.\r
2343 //\r
2344 } else {\r
2345 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2346 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2347 if (Key.ScanCode == SCAN_F9) {\r
2348 //\r
2349 // Reset to standard default\r
2350 //\r
2351 DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
2352 }\r
2353 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2354 break;\r
2355 }\r
2356 }\r
2357 }\r
2358 break;\r
2359 }\r
2360 break;\r
2361\r
2362 case CfScreenOperation:\r
2363 if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
2364 //\r
2365 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
2366 // ignore the selection and go back to reading keys.\r
2367 //\r
2368 if (IsListEmpty (&Menu)) {\r
2369 ControlFlag = CfReadKey;\r
2370 break;\r
2371 }\r
2372 //\r
2373 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2374 //\r
2375 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
2376 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2377 if (IsSelectable (NextMenuOption)) {\r
2378 break;\r
2379 }\r
2380 }\r
2381\r
2382 if (Link == &Menu) {\r
2383 ControlFlag = CfPrepareToReadKey;\r
2384 break;\r
2385 }\r
2386 } else if (ScreenOperation == UiReset) {\r
2387 //\r
2388 // Press ESC to exit FormSet\r
2389 //\r
2390 Selection->Action = UI_ACTION_EXIT;\r
2391 Selection->Statement = NULL;\r
2392 }\r
2393\r
2394 for (Index = 0;\r
2395 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2396 Index++\r
2397 ) {\r
2398 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2399 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2400 break;\r
2401 }\r
2402 }\r
2403 break;\r
2404\r
2405 case CfUiPrevious:\r
2406 ControlFlag = CfCheckSelection;\r
2407\r
2408 if (IsListEmpty (&gMenuList)) {\r
2409 Selection->Action = UI_ACTION_NONE;\r
2410 if (IsListEmpty (&Menu)) {\r
2411 ControlFlag = CfReadKey;\r
2412 }\r
2413 break;\r
2414 }\r
2415\r
2416 //\r
2417 // Remove the Cached page entry\r
2418 //\r
2419 UiRemoveMenuListEntry (Selection);\r
2420\r
2421 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2422 Selection->Statement = NULL;\r
2423 break;\r
2424\r
2425 case CfUiSelect:\r
2426 ControlFlag = CfCheckSelection;\r
2427\r
2428 Statement = MenuOption->ThisTag;\r
2429 if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
2430 (Statement->Operand == EFI_IFR_DATE_OP) ||\r
2431 (Statement->Operand == EFI_IFR_TIME_OP) ||\r
2432 (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
2433 break;\r
2434 }\r
2435\r
2436 //\r
2437 // Keep highlight on current MenuOption\r
2438 //\r
2439 Selection->QuestionId = Statement->QuestionId;\r
2440\r
2441 switch (Statement->Operand) {\r
2442 case EFI_IFR_REF_OP:\r
2443 if (Statement->RefDevicePath != 0) {\r
2444 //\r
2445 // Goto another Hii Package list\r
2446 //\r
2447 ControlFlag = CfUiReset;\r
2448 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
2449\r
2450 StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
2451 if (StringPtr == NULL) {\r
2452 //\r
2453 // No device path string not found, exit\r
2454 //\r
2455 Selection->Action = UI_ACTION_EXIT;\r
2456 Selection->Statement = NULL;\r
2457 break;\r
2458 }\r
2459 BufferSize = StrLen (StringPtr) / 2;\r
2460 DevicePath = AllocatePool (BufferSize);\r
63d55bb9
LG
2461 \r
2462 //\r
2463 // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
2464 //\r
2465 DevicePathBuffer = (UINT8 *) DevicePath;\r
2466 for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
2467 TemStr[0] = StringPtr[Index];\r
2468 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
2469 if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
2470 //\r
2471 // Invalid Hex Char as the tail.\r
2472 //\r
2473 break;\r
2474 }\r
2475 if ((Index & 1) == 0) {\r
2476 DevicePathBuffer [Index/2] = DigitUint8;\r
2477 } else {\r
2478 DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
2479 }\r
2480 }\r
7936fb6a 2481\r
cb7d01c0 2482 Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
7936fb6a 2483 if (Selection->Handle == NULL) {\r
2484 //\r
2485 // If target Hii Handle not found, exit\r
2486 //\r
2487 Selection->Action = UI_ACTION_EXIT;\r
2488 Selection->Statement = NULL;\r
2489 break;\r
2490 }\r
2491\r
f4113e1f 2492 FreePool (StringPtr);\r
2493 FreePool (DevicePath);\r
7936fb6a 2494\r
2495 CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
2496 Selection->FormId = Statement->RefFormId;\r
2497 Selection->QuestionId = Statement->RefQuestionId;\r
2498 } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
2499 //\r
2500 // Goto another Formset, check for uncommitted data\r
2501 //\r
2502 ControlFlag = CfUiReset;\r
2503 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
2504\r
2505 CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
2506 Selection->FormId = Statement->RefFormId;\r
2507 Selection->QuestionId = Statement->RefQuestionId;\r
2508 } else if (Statement->RefFormId != 0) {\r
2509 //\r
2510 // Goto another form inside this formset,\r
2511 //\r
2512 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2513\r
2514 //\r
2515 // Link current form so that we can always go back when someone hits the UiPrevious\r
2516 //\r
2517 UiAddMenuListEntry (Selection);\r
2518\r
2519 Selection->FormId = Statement->RefFormId;\r
2520 Selection->QuestionId = Statement->RefQuestionId;\r
2521 } else if (Statement->RefQuestionId != 0) {\r
2522 //\r
2523 // Goto another Question\r
2524 //\r
2525 Selection->QuestionId = Statement->RefQuestionId;\r
2526\r
2527 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
2528 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2529 } else {\r
2530 Repaint = TRUE;\r
2531 NewLine = TRUE;\r
2532 break;\r
2533 }\r
2534 }\r
2535 break;\r
2536\r
2537 case EFI_IFR_ACTION_OP:\r
2538 //\r
2539 // Process the Config string <ConfigResp>\r
2540 //\r
2541 Status = ProcessQuestionConfig (Selection, Statement);\r
2542\r
2543 if (EFI_ERROR (Status)) {\r
2544 break;\r
2545 }\r
2546\r
2547 //\r
2548 // The action button may change some Question value, so refresh the form\r
2549 //\r
2550 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2551 break;\r
2552\r
2553 case EFI_IFR_RESET_BUTTON_OP:\r
2554 //\r
2555 // Reset Question to default value specified by DefaultId\r
2556 //\r
2557 ControlFlag = CfUiDefault;\r
2558 DefaultId = Statement->DefaultId;\r
2559 break;\r
2560\r
2561 default:\r
2562 //\r
2563 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
2564 //\r
2565 UpdateKeyHelp (MenuOption, TRUE);\r
2566 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
2567\r
2568 if (EFI_ERROR (Status)) {\r
2569 Repaint = TRUE;\r
2570 NewLine = TRUE;\r
8d00a0f1 2571 UpdateKeyHelp (MenuOption, FALSE);\r
2572 } else {\r
2573 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2574 }\r
7936fb6a 2575\r
8d00a0f1 2576 if (OptionString != NULL) {\r
2577 FreePool (OptionString);\r
2578 }\r
7936fb6a 2579 break;\r
2580 }\r
2581 break;\r
2582\r
2583 case CfUiReset:\r
2584 //\r
2585 // We are going to leave current FormSet, so check uncommited data in this FormSet\r
2586 //\r
2587 ControlFlag = CfCheckSelection;\r
2588\r
0a1147ed 2589 if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 2590 //\r
2591 // There is no parent menu for FrontPage\r
2592 //\r
2593 Selection->Action = UI_ACTION_NONE;\r
2594 Selection->Statement = MenuOption->ThisTag;\r
2595 break;\r
2596 }\r
2597\r
2598 //\r
2599 // If NV flag is up, prompt user\r
2600 //\r
2601 if (gNvUpdateRequired) {\r
2602 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2603\r
2604 YesResponse = gYesResponse[0];\r
2605 NoResponse = gNoResponse[0];\r
2606\r
2607 do {\r
2608 CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
2609 } while\r
2610 (\r
2611 (Key.ScanCode != SCAN_ESC) &&\r
2612 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
2613 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
2614 );\r
2615\r
2616 //\r
2617 // If the user hits the YesResponse key\r
2618 //\r
2619 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
2620 } else {\r
2621 Repaint = TRUE;\r
2622 NewLine = TRUE;\r
2623\r
2624 Selection->Action = UI_ACTION_NONE;\r
2625 break;\r
2626 }\r
2627 }\r
2628\r
2629 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2630 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
2631\r
2632 UiFreeMenuList ();\r
2633 gST->ConOut->ClearScreen (gST->ConOut);\r
2634 return EFI_SUCCESS;\r
2635\r
2636 case CfUiLeft:\r
2637 ControlFlag = CfCheckSelection;\r
2638 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2639 if (MenuOption->Sequence != 0) {\r
2640 //\r
2641 // In the middle or tail of the Date/Time op-code set, go left.\r
2642 //\r
2643 NewPos = NewPos->BackLink;\r
2644 }\r
2645 }\r
2646 break;\r
2647\r
2648 case CfUiRight:\r
2649 ControlFlag = CfCheckSelection;\r
2650 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2651 if (MenuOption->Sequence != 2) {\r
2652 //\r
2653 // In the middle or tail of the Date/Time op-code set, go left.\r
2654 //\r
2655 NewPos = NewPos->ForwardLink;\r
2656 }\r
2657 }\r
2658 break;\r
2659\r
2660 case CfUiUp:\r
2661 ControlFlag = CfCheckSelection;\r
2662\r
2663 SavedListEntry = TopOfScreen;\r
2664\r
2665 if (NewPos->BackLink != &Menu) {\r
2666 NewLine = TRUE;\r
2667 //\r
2668 // Adjust Date/Time position before we advance forward.\r
2669 //\r
2670 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2671\r
2672 //\r
2673 // Caution that we have already rewind to the top, don't go backward in this situation.\r
2674 //\r
2675 if (NewPos->BackLink != &Menu) {\r
2676 NewPos = NewPos->BackLink;\r
2677 }\r
2678\r
2679 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2680 DistanceValue = PreviousMenuOption->Skip;\r
2681\r
2682 //\r
2683 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
2684 // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
2685 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2686 // checking can be done.\r
2687 //\r
2688 DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\r
2689\r
2690 //\r
2691 // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
2692 // don't worry about a redraw.\r
2693 //\r
2694 if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
2695 Repaint = TRUE;\r
2696 TopOfScreen = NewPos;\r
2697 }\r
2698\r
747b19ea 2699 Difference = MoveToNextStatement (TRUE, &NewPos);\r
e3eb7467 2700 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2701 DistanceValue += PreviousMenuOption->Skip;\r
2702 \r
747b19ea 2703 if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
7936fb6a 2704 if (Difference > 0) {\r
2705 //\r
2706 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
2707 //\r
2708 TopOfScreen = NewPos;\r
2709 Repaint = TRUE;\r
747b19ea 2710 SkipValue = 0;\r
2711 OldSkipValue = 0;\r
7936fb6a 2712 }\r
2713 }\r
2714 if (Difference < 0) {\r
2715 //\r
2716 // We want to goto previous MenuOption, but finally we go down.\r
2717 // it means that we hit the begining MenuOption that can be focused\r
2718 // so we simply scroll to the top\r
2719 //\r
2720 if (SavedListEntry != Menu.ForwardLink) {\r
2721 TopOfScreen = Menu.ForwardLink;\r
2722 Repaint = TRUE;\r
2723 }\r
2724 }\r
2725\r
2726 //\r
2727 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2728 //\r
2729 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2730\r
2731 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
2732 } else {\r
2733 SavedMenuOption = MenuOption;\r
2734 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2735 if (!IsSelectable (MenuOption)) {\r
2736 //\r
2737 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2738 //\r
2739 ScreenOperation = UiDown;\r
2740 ControlFlag = CfScreenOperation;\r
2741 break;\r
2742 }\r
2743\r
2744 MenuOption = SavedMenuOption;\r
2745 }\r
2746 break;\r
2747\r
2748 case CfUiPageUp:\r
2749 ControlFlag = CfCheckSelection;\r
2750\r
2751 if (NewPos->BackLink == &Menu) {\r
2752 NewLine = FALSE;\r
2753 Repaint = FALSE;\r
2754 break;\r
2755 }\r
2756\r
2757 NewLine = TRUE;\r
2758 Repaint = TRUE;\r
2759 Link = TopOfScreen;\r
2760 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2761 Index = BottomRow;\r
2762 while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
2763 Index = Index - PreviousMenuOption->Skip;\r
2764 Link = Link->BackLink;\r
2765 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2766 }\r
2767\r
2768 TopOfScreen = Link;\r
2769 Difference = MoveToNextStatement (TRUE, &Link);\r
2770 if (Difference > 0) {\r
2771 //\r
2772 // The focus MenuOption is above the TopOfScreen\r
2773 //\r
2774 TopOfScreen = Link;\r
2775 } else if (Difference < 0) {\r
2776 //\r
2777 // This happens when there is no MenuOption can be focused from\r
2778 // Current MenuOption to the first MenuOption\r
2779 //\r
2780 TopOfScreen = Menu.ForwardLink;\r
2781 }\r
2782 Index += Difference;\r
2783 if (Index < TopRow) {\r
2784 MenuOption = NULL;\r
2785 }\r
2786\r
2787 if (NewPos == Link) {\r
2788 Repaint = FALSE;\r
2789 NewLine = FALSE;\r
2790 } else {\r
2791 NewPos = Link;\r
2792 }\r
2793\r
2794 //\r
2795 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2796 // Don't do this when we are already in the first page.\r
2797 //\r
2798 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2799 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2800 break;\r
2801\r
2802 case CfUiPageDown:\r
2803 ControlFlag = CfCheckSelection;\r
2804\r
2805 if (NewPos->ForwardLink == &Menu) {\r
2806 NewLine = FALSE;\r
2807 Repaint = FALSE;\r
2808 break;\r
2809 }\r
2810\r
2811 NewLine = TRUE;\r
2812 Repaint = TRUE;\r
2813 Link = TopOfScreen;\r
2814 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2815 Index = TopRow;\r
2816 while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {\r
2817 Index = Index + NextMenuOption->Skip;\r
2818 Link = Link->ForwardLink;\r
2819 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2820 }\r
2821\r
2822 Index += MoveToNextStatement (FALSE, &Link);\r
2823 if (Index > BottomRow) {\r
2824 //\r
2825 // There are more MenuOption needing scrolling\r
2826 //\r
2827 TopOfScreen = Link;\r
2828 MenuOption = NULL;\r
2829 }\r
2830 if (NewPos == Link && Index <= BottomRow) {\r
2831 //\r
2832 // Finally we know that NewPos is the last MenuOption can be focused.\r
2833 //\r
2834 NewLine = FALSE;\r
2835 Repaint = FALSE;\r
2836 } else {\r
2837 NewPos = Link;\r
2838 }\r
2839\r
2840 //\r
2841 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2842 // Don't do this when we are already in the last page.\r
2843 //\r
2844 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2845 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2846 break;\r
2847\r
2848 case CfUiDown:\r
2849 ControlFlag = CfCheckSelection;\r
2850 //\r
2851 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
2852 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
2853 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2854 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
2855 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
2856 // the Date/Time op-code.\r
2857 //\r
2858 SavedListEntry = NewPos;\r
2859 DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos);\r
2860\r
2861 if (NewPos->ForwardLink != &Menu) {\r
2862 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2863 NewLine = TRUE;\r
2864 NewPos = NewPos->ForwardLink;\r
2865 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2866\r
2867 DistanceValue += NextMenuOption->Skip;\r
2868 DistanceValue += MoveToNextStatement (FALSE, &NewPos);\r
2869 //\r
2870 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
2871 //\r
2872 UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
2873\r
2874 Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
2875 if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
2876 (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
2877 NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2878 ) {\r
2879 Temp ++;\r
2880 }\r
2881\r
2882 //\r
2883 // If we are going to scroll, update TopOfScreen\r
2884 //\r
2885 if (Temp > BottomRow) {\r
2886 do {\r
2887 //\r
2888 // Is the current top of screen a zero-advance op-code?\r
2889 // If so, keep moving forward till we hit a >0 advance op-code\r
2890 //\r
2891 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2892\r
2893 //\r
2894 // If bottom op-code is more than one line or top op-code is more than one line\r
2895 //\r
2896 if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {\r
2897 //\r
2898 // Is the bottom op-code greater than or equal in size to the top op-code?\r
2899 //\r
2900 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
2901 //\r
2902 // Skip the top op-code\r
2903 //\r
2904 TopOfScreen = TopOfScreen->ForwardLink;\r
2905 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
2906\r
2907 OldSkipValue = Difference;\r
2908\r
2909 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2910\r
2911 //\r
2912 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
2913 //\r
2914 for (;\r
2915 Difference >= (INTN) SavedMenuOption->Skip;\r
2916 Difference = Difference - (INTN) SavedMenuOption->Skip\r
2917 ) {\r
2918 //\r
2919 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
2920 //\r
2921 TopOfScreen = TopOfScreen->ForwardLink;\r
2922 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2923 if (Difference < (INTN) SavedMenuOption->Skip) {\r
2924 Difference = SavedMenuOption->Skip - Difference - 1;\r
2925 break;\r
2926 } else {\r
2927 if (Difference == (INTN) SavedMenuOption->Skip) {\r
2928 TopOfScreen = TopOfScreen->ForwardLink;\r
2929 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
2930 Difference = SavedMenuOption->Skip - Difference;\r
2931 break;\r
2932 }\r
2933 }\r
2934 }\r
2935 //\r
2936 // Since we will act on this op-code in the next routine, and increment the\r
2937 // SkipValue, set the skips to one less than what is required.\r
2938 //\r
2939 SkipValue = Difference - 1;\r
2940\r
2941 } else {\r
2942 //\r
2943 // Since we will act on this op-code in the next routine, and increment the\r
2944 // SkipValue, set the skips to one less than what is required.\r
2945 //\r
2946 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
2947 }\r
2948 } else {\r
2949 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
2950 TopOfScreen = TopOfScreen->ForwardLink;\r
2951 break;\r
2952 } else {\r
2953 SkipValue = OldSkipValue;\r
2954 }\r
2955 }\r
2956 //\r
2957 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
2958 // Let's set a skip flag to smoothly scroll the top of the screen.\r
2959 //\r
2960 if (SavedMenuOption->Skip > 1) {\r
2961 if (SavedMenuOption == NextMenuOption) {\r
2962 SkipValue = 0;\r
2963 } else {\r
2964 SkipValue++;\r
2965 }\r
2966 } else {\r
2967 SkipValue = 0;\r
2968 TopOfScreen = TopOfScreen->ForwardLink;\r
2969 }\r
2970 } while (SavedMenuOption->Skip == 0);\r
2971\r
2972 Repaint = TRUE;\r
2973 OldSkipValue = SkipValue;\r
2974 }\r
2975\r
2976 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
2977\r
2978 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
2979\r
2980 } else {\r
2981 SavedMenuOption = MenuOption;\r
2982 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2983 if (!IsSelectable (MenuOption)) {\r
2984 //\r
2985 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2986 //\r
2987 ScreenOperation = UiUp;\r
2988 ControlFlag = CfScreenOperation;\r
2989 break;\r
2990 }\r
2991\r
2992 MenuOption = SavedMenuOption;\r
2993 //\r
2994 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
2995 //\r
2996 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2997 }\r
2998 break;\r
2999\r
3000 case CfUiSave:\r
3001 ControlFlag = CfCheckSelection;\r
3002\r
3003 //\r
3004 // Submit the form\r
3005 //\r
3006 Status = SubmitForm (Selection->FormSet, Selection->Form);\r
3007\r
3008 if (!EFI_ERROR (Status)) {\r
3009 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3010 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3011 } else {\r
3012 do {\r
3013 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
3014 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3015\r
3016 Repaint = TRUE;\r
3017 NewLine = TRUE;\r
3018 }\r
3019 break;\r
3020\r
3021 case CfUiDefault:\r
3022 ControlFlag = CfCheckSelection;\r
3023\r
3024 Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
3025\r
3026 if (!EFI_ERROR (Status)) {\r
3027 Selection->Action = UI_ACTION_REFRESH_FORM;\r
ebe43565 3028 Selection->Statement = NULL;\r
7936fb6a 3029\r
3030 //\r
3031 // Show NV update flag on status bar\r
3032 //\r
3033 gNvUpdateRequired = TRUE;\r
3034 }\r
3035 break;\r
3036\r
3037 case CfUiNoOperation:\r
3038 ControlFlag = CfCheckSelection;\r
3039 break;\r
3040\r
3041 case CfExit:\r
3042 UiFreeRefreshList ();\r
3043\r
3044 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
3045 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3046 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3047 gST->ConOut->OutputString (gST->ConOut, L"\n");\r
3048\r
3049 return EFI_SUCCESS;\r
3050\r
3051 default:\r
3052 break;\r
3053 }\r
3054 }\r
3055}\r