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