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