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