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