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