]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Print Arrow for Goto button.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
CommitLineData
7936fb6a 1/** @file\r
2Utility functions for User Interface functions.\r
3\r
e5eed7d3
HT
4Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
344 EFI_HII_VALUE *HiiValue;\r
345 EFI_BROWSER_ACTION_REQUEST ActionRequest;\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
377 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
f4113e1f 378 FreePool (OptionString);\r
8d00a0f1 379 }\r
380\r
7936fb6a 381 //\r
8d00a0f1 382 // Question value may be changed, need invoke its Callback()\r
7936fb6a 383 //\r
8d00a0f1 384 ConfigAccess = Selection->FormSet->ConfigAccess;\r
7064c0a5 385 if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
8d00a0f1 386 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
7936fb6a 387\r
8d00a0f1 388 HiiValue = &Question->HiiValue;\r
389 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
390 //\r
391 // Create String in HII database for Configuration Driver to retrieve\r
392 //\r
393 HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, Selection->FormSet->HiiHandle);\r
7936fb6a 394 }\r
395\r
8d00a0f1 396 Status = ConfigAccess->Callback (\r
397 ConfigAccess,\r
398 EFI_BROWSER_ACTION_CHANGING,\r
399 Question->QuestionId,\r
400 HiiValue->Type,\r
401 &HiiValue->Value,\r
402 &ActionRequest\r
403 );\r
7936fb6a 404\r
8d00a0f1 405 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
7936fb6a 406 //\r
8d00a0f1 407 // Clean the String in HII Database\r
7936fb6a 408 //\r
8d00a0f1 409 DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
410 }\r
7936fb6a 411\r
8d00a0f1 412 if (!EFI_ERROR (Status)) {\r
413 switch (ActionRequest) {\r
414 case EFI_BROWSER_ACTION_REQUEST_RESET:\r
415 gResetRequired = TRUE;\r
416 break;\r
7936fb6a 417\r
8d00a0f1 418 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
419 SubmitForm (Selection->FormSet, Selection->Form);\r
420 break;\r
7936fb6a 421\r
8d00a0f1 422 case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
423 Selection->Action = UI_ACTION_EXIT;\r
424 gNvUpdateRequired = FALSE;\r
425 break;\r
426\r
427 default:\r
428 break;\r
429 }\r
7936fb6a 430 }\r
431 }\r
432\r
433 MenuRefreshEntry = MenuRefreshEntry->Next;\r
434\r
435 } while (MenuRefreshEntry != NULL);\r
8d00a0f1 436\r
437 if (mHiiPackageListUpdated) {\r
438 //\r
439 // Package list is updated, force to reparse IFR binary of target Formset\r
440 //\r
441 mHiiPackageListUpdated = FALSE;\r
442 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
443 return EFI_SUCCESS;\r
444 }\r
7936fb6a 445 }\r
8d00a0f1 446\r
447 return EFI_TIMEOUT;\r
7936fb6a 448}\r
449\r
450\r
451/**\r
452 Wait for a given event to fire, or for an optional timeout to expire.\r
453\r
454 @param Event The event to wait for\r
455 @param Timeout An optional timeout value in 100 ns units.\r
456 @param RefreshInterval Menu refresh interval (in seconds).\r
457\r
458 @retval EFI_SUCCESS Event fired before Timeout expired.\r
459 @retval EFI_TIME_OUT Timout expired before Event fired.\r
460\r
461**/\r
462EFI_STATUS\r
463UiWaitForSingleEvent (\r
464 IN EFI_EVENT Event,\r
465 IN UINT64 Timeout, OPTIONAL\r
466 IN UINT8 RefreshInterval OPTIONAL\r
467 )\r
468{\r
469 EFI_STATUS Status;\r
470 UINTN Index;\r
471 EFI_EVENT TimerEvent;\r
472 EFI_EVENT WaitList[2];\r
473\r
474 if (Timeout != 0) {\r
475 //\r
476 // Create a timer event\r
477 //\r
478 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
479 if (!EFI_ERROR (Status)) {\r
480 //\r
481 // Set the timer event\r
482 //\r
483 gBS->SetTimer (\r
484 TimerEvent,\r
485 TimerRelative,\r
486 Timeout\r
487 );\r
488\r
489 //\r
490 // Wait for the original event or the timer\r
491 //\r
492 WaitList[0] = Event;\r
493 WaitList[1] = TimerEvent;\r
494 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
495 gBS->CloseEvent (TimerEvent);\r
496\r
497 //\r
498 // If the timer expired, change the return to timed out\r
499 //\r
500 if (!EFI_ERROR (Status) && Index == 1) {\r
501 Status = EFI_TIMEOUT;\r
502 }\r
503 }\r
504 } else {\r
505 //\r
506 // Update screen every second\r
507 //\r
508 if (RefreshInterval == 0) {\r
509 Timeout = ONE_SECOND;\r
510 } else {\r
511 Timeout = RefreshInterval * ONE_SECOND;\r
512 }\r
513\r
514 do {\r
515 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
516\r
517 //\r
518 // Set the timer event\r
519 //\r
520 gBS->SetTimer (\r
521 TimerEvent,\r
522 TimerRelative,\r
523 Timeout\r
524 );\r
525\r
526 //\r
527 // Wait for the original event or the timer\r
528 //\r
529 WaitList[0] = Event;\r
530 WaitList[1] = TimerEvent;\r
531 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
532\r
533 //\r
534 // If the timer expired, update anything that needs a refresh and keep waiting\r
535 //\r
536 if (!EFI_ERROR (Status) && Index == 1) {\r
537 Status = EFI_TIMEOUT;\r
538 if (RefreshInterval != 0) {\r
8d00a0f1 539 Status = RefreshForm ();\r
7936fb6a 540 }\r
541 }\r
542\r
543 gBS->CloseEvent (TimerEvent);\r
544 } while (Status == EFI_TIMEOUT);\r
545 }\r
546\r
547 return Status;\r
548}\r
549\r
550\r
551/**\r
552 Add one menu option by specified description and context.\r
553\r
554 @param String String description for this option.\r
555 @param Handle Hii handle for the package list.\r
556 @param Statement Statement of this Menu Option.\r
557 @param NumberOfLines Display lines for this Menu Option.\r
558 @param MenuItemCount The index for this Option in the Menu.\r
559\r
8b0fc5c1 560 @retval Pointer Pointer to the added Menu Option.\r
561\r
7936fb6a 562**/\r
8b0fc5c1 563UI_MENU_OPTION *\r
7936fb6a 564UiAddMenuOption (\r
565 IN CHAR16 *String,\r
566 IN EFI_HII_HANDLE Handle,\r
567 IN FORM_BROWSER_STATEMENT *Statement,\r
568 IN UINT16 NumberOfLines,\r
569 IN UINT16 MenuItemCount\r
570 )\r
571{\r
572 UI_MENU_OPTION *MenuOption;\r
573 UINTN Index;\r
574 UINTN Count;\r
575\r
576 Count = 1;\r
8b0fc5c1 577 MenuOption = NULL;\r
7936fb6a 578\r
579 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
580 //\r
581 // Add three MenuOptions for Date/Time\r
582 // Data format : [01/02/2004] [11:22:33]\r
583 // Line number : 0 0 1 0 0 1\r
584 //\r
585 NumberOfLines = 0;\r
586 Count = 3;\r
587\r
588 if (Statement->Storage == NULL) {\r
589 //\r
590 // For RTC type of date/time, set default refresh interval to be 1 second\r
591 //\r
592 if (Statement->RefreshInterval == 0) {\r
593 Statement->RefreshInterval = 1;\r
594 }\r
595 }\r
596 }\r
597\r
598 for (Index = 0; Index < Count; Index++) {\r
599 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
600 ASSERT (MenuOption);\r
601\r
602 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
603 MenuOption->Description = String;\r
604 MenuOption->Handle = Handle;\r
605 MenuOption->ThisTag = Statement;\r
606 MenuOption->EntryNumber = MenuItemCount;\r
607\r
608 if (Index == 2) {\r
609 //\r
610 // Override LineNumber for the MenuOption in Date/Time sequence\r
611 //\r
612 MenuOption->Skip = 1;\r
613 } else {\r
614 MenuOption->Skip = NumberOfLines;\r
615 }\r
616 MenuOption->Sequence = Index;\r
617\r
618 if (Statement->GrayOutExpression != NULL) {\r
619 MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
620 }\r
621\r
8b0fc5c1 622 switch (Statement->Operand) {\r
623 case EFI_IFR_ORDERED_LIST_OP:\r
624 case EFI_IFR_ONE_OF_OP:\r
625 case EFI_IFR_NUMERIC_OP:\r
626 case EFI_IFR_TIME_OP:\r
627 case EFI_IFR_DATE_OP:\r
628 case EFI_IFR_CHECKBOX_OP:\r
629 case EFI_IFR_PASSWORD_OP:\r
630 case EFI_IFR_STRING_OP:\r
631 //\r
632 // User could change the value of these items\r
633 //\r
634 MenuOption->IsQuestion = TRUE;\r
635 break;\r
636\r
637 default:\r
638 MenuOption->IsQuestion = FALSE;\r
639 break;\r
640 }\r
641\r
7936fb6a 642 if ((Statement->ValueExpression != NULL) ||\r
643 ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
644 MenuOption->ReadOnly = TRUE;\r
645 }\r
646\r
ce6d12cc 647 InsertTailList (&gMenuOption, &MenuOption->Link);\r
7936fb6a 648 }\r
8b0fc5c1 649\r
650 return MenuOption;\r
7936fb6a 651}\r
652\r
653\r
654/**\r
655 Routine used to abstract a generic dialog interface and return the selected key or string\r
656\r
657 @param NumberOfLines The number of lines for the dialog box\r
658 @param HotKey Defines whether a single character is parsed\r
659 (TRUE) and returned in KeyValue or a string is\r
660 returned in StringBuffer. Two special characters\r
661 are considered when entering a string, a SCAN_ESC\r
662 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates\r
663 string input and returns\r
664 @param MaximumStringSize The maximum size in bytes of a typed in string\r
665 (each character is a CHAR16) and the minimum\r
666 string returned is two bytes\r
667 @param StringBuffer The passed in pointer to the buffer which will\r
668 hold the typed in string if HotKey is FALSE\r
669 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
7936fb6a 670 @param ... A series of (quantity == NumberOfLines) text\r
671 strings which will be used to construct the dialog\r
672 box\r
673\r
674 @retval EFI_SUCCESS Displayed dialog and received user interaction\r
675 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.\r
676 (StringBuffer == NULL) && (HotKey == FALSE))\r
677 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine\r
678\r
679**/\r
680EFI_STATUS\r
8091267c 681EFIAPI\r
7936fb6a 682CreateDialog (\r
683 IN UINTN NumberOfLines,\r
684 IN BOOLEAN HotKey,\r
685 IN UINTN MaximumStringSize,\r
686 OUT CHAR16 *StringBuffer,\r
687 OUT EFI_INPUT_KEY *KeyValue,\r
7936fb6a 688 ...\r
689 )\r
690{\r
691 VA_LIST Marker;\r
692 UINTN Count;\r
693 EFI_INPUT_KEY Key;\r
694 UINTN LargestString;\r
695 CHAR16 *TempString;\r
696 CHAR16 *BufferedString;\r
697 CHAR16 *StackString;\r
698 CHAR16 KeyPad[2];\r
699 UINTN Start;\r
700 UINTN Top;\r
701 UINTN Index;\r
702 EFI_STATUS Status;\r
703 BOOLEAN SelectionComplete;\r
704 UINTN InputOffset;\r
705 UINTN CurrentAttribute;\r
706 UINTN DimensionsWidth;\r
707 UINTN DimensionsHeight;\r
708\r
709 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
710 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
711\r
712 SelectionComplete = FALSE;\r
713 InputOffset = 0;\r
714 TempString = AllocateZeroPool (MaximumStringSize * 2);\r
715 BufferedString = AllocateZeroPool (MaximumStringSize * 2);\r
716 CurrentAttribute = gST->ConOut->Mode->Attribute;\r
717\r
718 ASSERT (TempString);\r
719 ASSERT (BufferedString);\r
720\r
f4bcc90f 721 VA_START (Marker, KeyValue);\r
7936fb6a 722\r
723 //\r
724 // Zero the outgoing buffer\r
725 //\r
726 ZeroMem (StringBuffer, MaximumStringSize);\r
727\r
728 if (HotKey) {\r
729 if (KeyValue == NULL) {\r
730 return EFI_INVALID_PARAMETER;\r
731 }\r
732 } else {\r
733 if (StringBuffer == NULL) {\r
734 return EFI_INVALID_PARAMETER;\r
735 }\r
736 }\r
737 //\r
738 // Disable cursor\r
739 //\r
740 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
741\r
f4bcc90f 742 LargestString = 0;\r
7936fb6a 743\r
7936fb6a 744 //\r
745 // Determine the largest string in the dialog box\r
746 // Notice we are starting with 1 since String is the first string\r
747 //\r
f4bcc90f 748 for (Count = 0; Count < NumberOfLines; Count++) {\r
7936fb6a 749 StackString = VA_ARG (Marker, CHAR16 *);\r
750\r
751 if (StackString[0] == L' ') {\r
752 InputOffset = Count + 1;\r
753 }\r
754\r
755 if ((GetStringWidth (StackString) / 2) > LargestString) {\r
756 //\r
757 // Size of the string visually and subtract the width by one for the null-terminator\r
758 //\r
759 LargestString = (GetStringWidth (StackString) / 2);\r
760 }\r
761 }\r
1c9a7554 762 VA_END (Marker);\r
7936fb6a 763\r
764 Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
765 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
766\r
767 Count = 0;\r
768\r
769 //\r
770 // Display the Popup\r
771 //\r
1c9a7554 772 VA_START (Marker, KeyValue);\r
773 CreateSharedPopUp (LargestString, NumberOfLines, Marker);\r
774 VA_END (Marker);\r
7936fb6a 775\r
776 //\r
777 // Take the first key typed and report it back?\r
778 //\r
779 if (HotKey) {\r
780 Status = WaitForKeyStroke (&Key);\r
781 ASSERT_EFI_ERROR (Status);\r
782 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
783\r
784 } else {\r
785 do {\r
786 Status = WaitForKeyStroke (&Key);\r
787\r
788 switch (Key.UnicodeChar) {\r
789 case CHAR_NULL:\r
790 switch (Key.ScanCode) {\r
791 case SCAN_ESC:\r
f4113e1f 792 FreePool (TempString);\r
793 FreePool (BufferedString);\r
7936fb6a 794 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
795 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
796 return EFI_DEVICE_ERROR;\r
797\r
798 default:\r
799 break;\r
800 }\r
801\r
802 break;\r
803\r
804 case CHAR_CARRIAGE_RETURN:\r
805 SelectionComplete = TRUE;\r
f4113e1f 806 FreePool (TempString);\r
807 FreePool (BufferedString);\r
7936fb6a 808 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
809 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
810 return EFI_SUCCESS;\r
811 break;\r
812\r
813 case CHAR_BACKSPACE:\r
814 if (StringBuffer[0] != CHAR_NULL) {\r
815 for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
816 TempString[Index] = StringBuffer[Index];\r
817 }\r
818 //\r
819 // Effectively truncate string by 1 character\r
820 //\r
821 TempString[Index - 1] = CHAR_NULL;\r
822 StrCpy (StringBuffer, TempString);\r
823 }\r
824\r
825 default:\r
826 //\r
827 // If it is the beginning of the string, don't worry about checking maximum limits\r
828 //\r
829 if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
830 StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
831 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
832 } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
833 KeyPad[0] = Key.UnicodeChar;\r
834 KeyPad[1] = CHAR_NULL;\r
835 StrCat (StringBuffer, KeyPad);\r
836 StrCat (TempString, KeyPad);\r
837 }\r
838 //\r
839 // If the width of the input string is now larger than the screen, we nee to\r
840 // adjust the index to start printing portions of the string\r
841 //\r
842 SetUnicodeMem (BufferedString, LargestString, L' ');\r
843\r
844 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
845\r
846 if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
847 Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
848 } else {\r
849 Index = 0;\r
850 }\r
851\r
852 for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
853 BufferedString[Count] = StringBuffer[Index];\r
854 }\r
855\r
856 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
857 break;\r
858 }\r
859 } while (!SelectionComplete);\r
860 }\r
861\r
862 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
863 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
864 return EFI_SUCCESS;\r
865}\r
866\r
867/**\r
868 Draw a pop up windows based on the dimension, number of lines and\r
869 strings specified.\r
870\r
871 @param RequestedWidth The width of the pop-up.\r
872 @param NumberOfLines The number of lines.\r
f4bcc90f 873 @param Marker The variable argument list for the list of string to be printed.\r
7936fb6a 874\r
875**/\r
876VOID\r
877CreateSharedPopUp (\r
878 IN UINTN RequestedWidth,\r
879 IN UINTN NumberOfLines,\r
f4bcc90f 880 IN VA_LIST Marker\r
7936fb6a 881 )\r
882{\r
883 UINTN Index;\r
884 UINTN Count;\r
885 CHAR16 Character;\r
886 UINTN Start;\r
887 UINTN End;\r
888 UINTN Top;\r
889 UINTN Bottom;\r
890 CHAR16 *String;\r
891 UINTN DimensionsWidth;\r
892 UINTN DimensionsHeight;\r
893\r
894 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
895 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
896\r
7936fb6a 897 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
898\r
899 if ((RequestedWidth + 2) > DimensionsWidth) {\r
900 RequestedWidth = DimensionsWidth - 2;\r
901 }\r
902\r
903 //\r
904 // Subtract the PopUp width from total Columns, allow for one space extra on\r
905 // each end plus a border.\r
906 //\r
907 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
908 End = Start + RequestedWidth + 1;\r
909\r
910 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
911 Bottom = Top + NumberOfLines + 2;\r
912\r
913 Character = BOXDRAW_DOWN_RIGHT;\r
914 PrintCharAt (Start, Top, Character);\r
915 Character = BOXDRAW_HORIZONTAL;\r
916 for (Index = Start; Index + 2 < End; Index++) {\r
917 PrintChar (Character);\r
918 }\r
919\r
920 Character = BOXDRAW_DOWN_LEFT;\r
921 PrintChar (Character);\r
922 Character = BOXDRAW_VERTICAL;\r
f4bcc90f 923\r
924 Count = 0;\r
925 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
926 String = VA_ARG (Marker, CHAR16*);\r
7936fb6a 927\r
928 //\r
929 // This will clear the background of the line - we never know who might have been\r
930 // here before us. This differs from the next clear in that it used the non-reverse\r
931 // video for normal printing.\r
932 //\r
933 if (GetStringWidth (String) / 2 > 1) {\r
934 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
935 }\r
936\r
937 //\r
938 // Passing in a space results in the assumption that this is where typing will occur\r
939 //\r
940 if (String[0] == L' ') {\r
941 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
942 }\r
943\r
944 //\r
945 // Passing in a NULL results in a blank space\r
946 //\r
947 if (String[0] == CHAR_NULL) {\r
948 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
949 }\r
950\r
951 PrintStringAt (\r
952 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
953 Index + 1,\r
954 String\r
955 );\r
956 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
957 PrintCharAt (Start, Index + 1, Character);\r
958 PrintCharAt (End - 1, Index + 1, Character);\r
959 }\r
960\r
961 Character = BOXDRAW_UP_RIGHT;\r
962 PrintCharAt (Start, Bottom - 1, Character);\r
963 Character = BOXDRAW_HORIZONTAL;\r
964 for (Index = Start; Index + 2 < End; Index++) {\r
965 PrintChar (Character);\r
966 }\r
967\r
968 Character = BOXDRAW_UP_LEFT;\r
969 PrintChar (Character);\r
970}\r
971\r
972/**\r
973 Draw a pop up windows based on the dimension, number of lines and\r
974 strings specified.\r
975\r
976 @param RequestedWidth The width of the pop-up.\r
977 @param NumberOfLines The number of lines.\r
7936fb6a 978 @param ... A series of text strings that displayed in the pop-up.\r
979\r
980**/\r
981VOID\r
8091267c 982EFIAPI\r
3ebb9bdb 983CreateMultiStringPopUp (\r
7936fb6a 984 IN UINTN RequestedWidth,\r
985 IN UINTN NumberOfLines,\r
7936fb6a 986 ...\r
987 )\r
988{\r
f4bcc90f 989 VA_LIST Marker;\r
990\r
991 VA_START (Marker, NumberOfLines);\r
d66e6c16 992\r
f4bcc90f 993 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
994\r
995 VA_END (Marker);\r
7936fb6a 996}\r
997\r
998\r
999/**\r
1000 Update status bar on the bottom of menu.\r
1001\r
1002 @param MessageType The type of message to be shown.\r
1003 @param Flags The flags in Question header.\r
1004 @param State Set or clear.\r
1005\r
1006**/\r
1007VOID\r
1008UpdateStatusBar (\r
1009 IN UINTN MessageType,\r
1010 IN UINT8 Flags,\r
1011 IN BOOLEAN State\r
1012 )\r
1013{\r
1014 UINTN Index;\r
7936fb6a 1015 CHAR16 *NvUpdateMessage;\r
1016 CHAR16 *InputErrorMessage;\r
1017\r
1018 NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
1019 InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
1020\r
1021 switch (MessageType) {\r
1022 case INPUT_ERROR:\r
1023 if (State) {\r
1024 gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
1025 PrintStringAt (\r
1026 gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
1027 gScreenDimensions.BottomRow - 1,\r
1028 InputErrorMessage\r
1029 );\r
19b15d63 1030 mInputError = TRUE;\r
7936fb6a 1031 } else {\r
1032 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
1033 for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
1034 PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" ");\r
1035 }\r
1036\r
19b15d63 1037 mInputError = FALSE;\r
7936fb6a 1038 }\r
1039 break;\r
1040\r
1041 case NV_UPDATE_REQUIRED:\r
40245175 1042 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
7936fb6a 1043 if (State) {\r
1044 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
1045 PrintStringAt (\r
1046 gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
1047 gScreenDimensions.BottomRow - 1,\r
1048 NvUpdateMessage\r
1049 );\r
1050 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
1051\r
1052 gNvUpdateRequired = TRUE;\r
1053 } else {\r
1054 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
1055 for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
1056 PrintAt (\r
1057 (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
1058 gScreenDimensions.BottomRow - 1,\r
1059 L" "\r
1060 );\r
1061 }\r
1062\r
1063 gNvUpdateRequired = FALSE;\r
1064 }\r
1065 }\r
1066 break;\r
1067\r
1068 case REFRESH_STATUS_BAR:\r
19b15d63 1069 if (mInputError) {\r
7936fb6a 1070 UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
1071 }\r
1072\r
1073 if (gNvUpdateRequired) {\r
1074 UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
1075 }\r
1076 break;\r
1077\r
1078 default:\r
1079 break;\r
1080 }\r
1081\r
f4113e1f 1082 FreePool (InputErrorMessage);\r
1083 FreePool (NvUpdateMessage);\r
7936fb6a 1084 return ;\r
1085}\r
1086\r
1087\r
1088/**\r
1089 Get the supported width for a particular op-code\r
1090\r
1091 @param Statement The FORM_BROWSER_STATEMENT structure passed in.\r
1092 @param Handle The handle in the HII database being used\r
1093\r
1094 @return Returns the number of CHAR16 characters that is support.\r
1095\r
1096**/\r
1097UINT16\r
1098GetWidth (\r
1099 IN FORM_BROWSER_STATEMENT *Statement,\r
1100 IN EFI_HII_HANDLE Handle\r
1101 )\r
1102{\r
1103 CHAR16 *String;\r
1104 UINTN Size;\r
1105 UINT16 Width;\r
1106\r
1107 Size = 0;\r
1108\r
1109 //\r
1110 // See if the second text parameter is really NULL\r
1111 //\r
1112 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1113 String = GetToken (Statement->TextTwo, Handle);\r
1114 Size = StrLen (String);\r
f4113e1f 1115 FreePool (String);\r
7936fb6a 1116 }\r
1117\r
1118 if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1119 (Statement->Operand == EFI_IFR_REF_OP) ||\r
1120 (Statement->Operand == EFI_IFR_PASSWORD_OP) ||\r
1121 (Statement->Operand == EFI_IFR_ACTION_OP) ||\r
1122 (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
1123 //\r
1124 // Allow a wide display if text op-code and no secondary text op-code\r
1125 //\r
1126 ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))\r
1127 ) {\r
1128 Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
1129 } else {\r
1130 Width = (UINT16) gPromptBlockWidth;\r
1131 }\r
1132\r
1133 if (Statement->InSubtitle) {\r
1134 Width -= SUBTITLE_INDENT;\r
1135 }\r
1136\r
f7a14a9b 1137 return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
7936fb6a 1138}\r
1139\r
7936fb6a 1140/**\r
1141 Will copy LineWidth amount of a string in the OutputString buffer and return the\r
1142 number of CHAR16 characters that were copied into the OutputString buffer.\r
1143\r
1144 @param InputString String description for this option.\r
1145 @param LineWidth Width of the desired string to extract in CHAR16\r
1146 characters\r
1147 @param Index Where in InputString to start the copy process\r
1148 @param OutputString Buffer to copy the string into\r
1149\r
1150 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
1151\r
1152**/\r
1153UINT16\r
1154GetLineByWidth (\r
1155 IN CHAR16 *InputString,\r
1156 IN UINT16 LineWidth,\r
1157 IN OUT UINTN *Index,\r
1158 OUT CHAR16 **OutputString\r
1159 )\r
1160{\r
1161 UINT16 Count;\r
1162 UINT16 Count2;\r
1163\r
1164 if (GetLineByWidthFinished) {\r
1165 GetLineByWidthFinished = FALSE;\r
1166 return (UINT16) 0;\r
1167 }\r
1168\r
1169 Count = LineWidth;\r
1170 Count2 = 0;\r
1171\r
1172 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
1173\r
1174 //\r
1175 // Ensure we have got a valid buffer\r
1176 //\r
1177 if (*OutputString != NULL) {\r
1178\r
1179 //\r
1180 //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
1181 //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
1182 //\r
1183 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
1184 *Index = *Index + 2;\r
1185 }\r
1186\r
1187 //\r
1188 // Fast-forward the string and see if there is a carriage-return in the string\r
1189 //\r
1190 for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
1191 ;\r
1192\r
1193 //\r
1194 // Copy the desired LineWidth of data to the output buffer.\r
1195 // Also make sure that we don't copy more than the string.\r
1196 // Also make sure that if there are linefeeds, we account for them.\r
1197 //\r
1198 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
1199 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
1200 ) {\r
1201 //\r
1202 // Convert to CHAR16 value and show that we are done with this operation\r
1203 //\r
1204 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
1205 if (LineWidth != 0) {\r
1206 GetLineByWidthFinished = TRUE;\r
1207 }\r
1208 } else {\r
1209 if (Count2 == LineWidth) {\r
1210 //\r
1211 // Rewind the string from the maximum size until we see a space to break the line\r
1212 //\r
1213 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
1214 ;\r
1215 if (LineWidth == 0) {\r
1216 LineWidth = Count;\r
1217 }\r
1218 } else {\r
1219 LineWidth = Count2;\r
1220 }\r
1221 }\r
1222\r
1223 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
1224\r
1225 //\r
1226 // If currently pointing to a space, increment the index to the first non-space character\r
1227 //\r
1228 for (;\r
1229 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
1230 (*Index)++\r
1231 )\r
1232 ;\r
1233 *Index = (UINT16) (*Index + LineWidth);\r
1234 return LineWidth;\r
1235 } else {\r
1236 return (UINT16) 0;\r
1237 }\r
1238}\r
1239\r
1240\r
1241/**\r
1242 Update display lines for a Menu Option.\r
1243\r
1244 @param Selection The user's selection.\r
1245 @param MenuOption The MenuOption to be checked.\r
1246 @param OptionalString The option string.\r
1247 @param SkipValue The number of lins to skip.\r
1248\r
7936fb6a 1249**/\r
1250VOID\r
1251UpdateOptionSkipLines (\r
1252 IN UI_MENU_SELECTION *Selection,\r
1253 IN UI_MENU_OPTION *MenuOption,\r
1254 OUT CHAR16 **OptionalString,\r
1255 IN UINTN SkipValue\r
1256 )\r
1257{\r
1258 UINTN Index;\r
1259 UINT16 Width;\r
1260 UINTN Row;\r
1261 UINTN OriginalRow;\r
1262 CHAR16 *OutputString;\r
1263 CHAR16 *OptionString;\r
1264\r
1265 Row = 0;\r
1266 OptionString = *OptionalString;\r
1267 OutputString = NULL;\r
1268\r
1269 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1270\r
1271 if (OptionString != NULL) {\r
1272 Width = (UINT16) gOptionBlockWidth;\r
1273\r
1274 OriginalRow = Row;\r
1275\r
1276 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1277 //\r
1278 // If there is more string to process print on the next row and increment the Skip value\r
1279 //\r
d1a54e2c 1280 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1281 if (SkipValue == 0) {\r
1282 Row++;\r
1283 //\r
1284 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1285 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1286 // some testing to ensure we are keeping this in-sync.\r
1287 //\r
1288 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1289 //\r
1290 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1291 MenuOption->Skip++;\r
1292 }\r
1293 }\r
1294 }\r
1295\r
f4113e1f 1296 FreePool (OutputString);\r
7936fb6a 1297 if (SkipValue != 0) {\r
1298 SkipValue--;\r
1299 }\r
1300 }\r
1301\r
1302 Row = OriginalRow;\r
1303 }\r
1304\r
1305 *OptionalString = OptionString;\r
1306}\r
1307\r
1308\r
1309/**\r
1310 Check whether this Menu Option could be highlighted.\r
1311\r
1312 This is an internal function.\r
1313\r
1314 @param MenuOption The MenuOption to be checked.\r
1315\r
1316 @retval TRUE This Menu Option is selectable.\r
1317 @retval FALSE This Menu Option could not be selected.\r
1318\r
1319**/\r
1320BOOLEAN\r
1321IsSelectable (\r
1322 UI_MENU_OPTION *MenuOption\r
1323 )\r
1324{\r
1325 if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1326 MenuOption->GrayOut || MenuOption->ReadOnly) {\r
1327 return FALSE;\r
1328 } else {\r
1329 return TRUE;\r
1330 }\r
1331}\r
1332\r
1333\r
1334/**\r
1335 Determine if the menu is the last menu that can be selected.\r
1336\r
1337 This is an internal function.\r
d66e6c16 1338\r
7936fb6a 1339 @param Direction The scroll direction. False is down. True is up.\r
1340 @param CurrentPos The current focus.\r
1341\r
1342 @return FALSE -- the menu isn't the last menu that can be selected.\r
1343 @return TRUE -- the menu is the last menu that can be selected.\r
1344\r
1345**/\r
1346BOOLEAN\r
1347ValueIsScroll (\r
1348 IN BOOLEAN Direction,\r
1349 IN LIST_ENTRY *CurrentPos\r
1350 )\r
1351{\r
1352 LIST_ENTRY *Temp;\r
1353 UI_MENU_OPTION *MenuOption;\r
1354\r
1355 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
1356\r
ce6d12cc 1357 if (Temp == &gMenuOption) {\r
7936fb6a 1358 return TRUE;\r
1359 }\r
1360\r
ce6d12cc 1361 for (; Temp != &gMenuOption; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
7936fb6a 1362 MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
1363 if (IsSelectable (MenuOption)) {\r
1364 return FALSE;\r
1365 }\r
1366 }\r
1367\r
1368 return TRUE;\r
1369}\r
1370\r
1371\r
1372/**\r
1373 Move to next selectable statement.\r
d66e6c16 1374\r
7936fb6a 1375 This is an internal function.\r
d66e6c16 1376\r
7936fb6a 1377 @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
1378 @param CurrentPosition Current position.\r
1379\r
1380 @return The row distance from current MenuOption to next selectable MenuOption.\r
1381\r
1382**/\r
1383INTN\r
1384MoveToNextStatement (\r
1385 IN BOOLEAN GoUp,\r
1386 IN OUT LIST_ENTRY **CurrentPosition\r
1387 )\r
1388{\r
1389 INTN Distance;\r
1390 LIST_ENTRY *Pos;\r
1391 BOOLEAN HitEnd;\r
1392 UI_MENU_OPTION *NextMenuOption;\r
1393\r
1394 Distance = 0;\r
1395 Pos = *CurrentPosition;\r
1396 HitEnd = FALSE;\r
1397\r
1398 while (TRUE) {\r
1399 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1400 if (IsSelectable (NextMenuOption)) {\r
1401 break;\r
1402 }\r
ce6d12cc 1403 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
7936fb6a 1404 HitEnd = TRUE;\r
1405 break;\r
1406 }\r
1407 Distance += NextMenuOption->Skip;\r
1408 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1409 }\r
1410\r
1411 if (HitEnd) {\r
1412 //\r
1413 // If we hit end there is still no statement can be focused,\r
1414 // we go backwards to find the statement can be focused.\r
1415 //\r
1416 Distance = 0;\r
1417 Pos = *CurrentPosition;\r
1418\r
1419 while (TRUE) {\r
1420 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
1421 if (IsSelectable (NextMenuOption)) {\r
1422 break;\r
1423 }\r
ce6d12cc 1424 if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
7936fb6a 1425 ASSERT (FALSE);\r
1426 break;\r
1427 }\r
1428 Distance -= NextMenuOption->Skip;\r
1429 Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
1430 }\r
1431 }\r
1432\r
1433 *CurrentPosition = &NextMenuOption->Link;\r
1434 return Distance;\r
1435}\r
1436\r
1437\r
1438/**\r
1439 Adjust Data and Time position accordingly.\r
1440 Data format : [01/02/2004] [11:22:33]\r
1441 Line number : 0 0 1 0 0 1\r
d66e6c16 1442\r
7936fb6a 1443 This is an internal function.\r
1444\r
1445 @param DirectionUp the up or down direction. False is down. True is\r
1446 up.\r
1447 @param CurrentPosition Current position. On return: Point to the last\r
1448 Option (Year or Second) if up; Point to the first\r
1449 Option (Month or Hour) if down.\r
1450\r
1451 @return Return line number to pad. It is possible that we stand on a zero-advance\r
1452 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
1453\r
1454**/\r
1455UINTN\r
1456AdjustDateAndTimePosition (\r
1457 IN BOOLEAN DirectionUp,\r
1458 IN OUT LIST_ENTRY **CurrentPosition\r
1459 )\r
1460{\r
1461 UINTN Count;\r
1462 LIST_ENTRY *NewPosition;\r
1463 UI_MENU_OPTION *MenuOption;\r
1464 UINTN PadLineNumber;\r
1465\r
1466 PadLineNumber = 0;\r
1467 NewPosition = *CurrentPosition;\r
1468 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1469\r
1470 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
1471 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
1472 //\r
1473 // Calculate the distance from current position to the last Date/Time MenuOption\r
1474 //\r
1475 Count = 0;\r
1476 while (MenuOption->Skip == 0) {\r
1477 Count++;\r
1478 NewPosition = NewPosition->ForwardLink;\r
1479 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1480 PadLineNumber = 1;\r
1481 }\r
1482\r
1483 NewPosition = *CurrentPosition;\r
1484 if (DirectionUp) {\r
1485 //\r
1486 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
1487 // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
1488 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
1489 // checking can be done.\r
1490 //\r
1491 while (Count++ < 2) {\r
1492 NewPosition = NewPosition->BackLink;\r
1493 }\r
1494 } else {\r
1495 //\r
1496 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
1497 // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
1498 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
1499 // checking can be done.\r
1500 //\r
1501 while (Count-- > 0) {\r
1502 NewPosition = NewPosition->ForwardLink;\r
1503 }\r
1504 }\r
1505\r
1506 *CurrentPosition = NewPosition;\r
1507 }\r
1508\r
1509 return PadLineNumber;\r
1510}\r
1511\r
cb7d01c0 1512/**\r
1513 Find HII Handle in the HII database associated with given Device Path.\r
1514\r
1515 If DevicePath is NULL, then ASSERT.\r
1516\r
1517 @param DevicePath Device Path associated with the HII package list\r
1518 handle.\r
1519\r
1520 @retval Handle HII package list Handle associated with the Device\r
1521 Path.\r
1522 @retval NULL Hii Package list handle is not found.\r
1523\r
1524**/\r
1525EFI_HII_HANDLE\r
1526EFIAPI\r
1527DevicePathToHiiHandle (\r
1528 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1529 )\r
1530{\r
1531 EFI_STATUS Status;\r
1532 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
1533 UINTN BufferSize;\r
1534 UINTN HandleCount;\r
1535 UINTN Index;\r
1536 EFI_HANDLE Handle;\r
1537 EFI_HANDLE DriverHandle;\r
1538 EFI_HII_HANDLE *HiiHandles;\r
1539 EFI_HII_HANDLE HiiHandle;\r
1540\r
1541 ASSERT (DevicePath != NULL);\r
1542\r
1543 TmpDevicePath = DevicePath;\r
1544 //\r
1545 // Locate Device Path Protocol handle buffer\r
1546 //\r
1547 Status = gBS->LocateDevicePath (\r
1548 &gEfiDevicePathProtocolGuid,\r
1549 &TmpDevicePath,\r
1550 &DriverHandle\r
1551 );\r
1552 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
1553 return NULL;\r
1554 }\r
1555\r
1556 //\r
1557 // Retrieve all HII Handles from HII database\r
1558 //\r
1559 BufferSize = 0x1000;\r
1560 HiiHandles = AllocatePool (BufferSize);\r
1561 ASSERT (HiiHandles != NULL);\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 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1570 FreePool (HiiHandles);\r
1571 HiiHandles = AllocatePool (BufferSize);\r
1572 ASSERT (HiiHandles != NULL);\r
1573\r
1574 Status = mHiiDatabase->ListPackageLists (\r
1575 mHiiDatabase,\r
1576 EFI_HII_PACKAGE_TYPE_ALL,\r
1577 NULL,\r
1578 &BufferSize,\r
1579 HiiHandles\r
1580 );\r
1581 }\r
1582\r
1583 if (EFI_ERROR (Status)) {\r
1584 FreePool (HiiHandles);\r
1585 return NULL;\r
1586 }\r
1587\r
1588 //\r
1589 // Search Hii Handle by Driver Handle\r
1590 //\r
1591 HiiHandle = NULL;\r
1592 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
1593 for (Index = 0; Index < HandleCount; Index++) {\r
1594 Status = mHiiDatabase->GetPackageListHandle (\r
1595 mHiiDatabase,\r
1596 HiiHandles[Index],\r
1597 &Handle\r
1598 );\r
1599 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
1600 HiiHandle = HiiHandles[Index];\r
1601 break;\r
1602 }\r
1603 }\r
1604\r
1605 FreePool (HiiHandles);\r
1606 return HiiHandle;\r
1607}\r
7936fb6a 1608\r
1609/**\r
1610 Display menu and wait for user to select one menu option, then return it.\r
1611 If AutoBoot is enabled, then if user doesn't select any option,\r
1612 after period of time, it will automatically return the first menu option.\r
1613\r
1614 @param Selection Menu selection.\r
1615\r
1616 @retval EFI_SUCESSS This function always return successfully for now.\r
1617\r
1618**/\r
1619EFI_STATUS\r
1620UiDisplayMenu (\r
1621 IN OUT UI_MENU_SELECTION *Selection\r
1622 )\r
1623{\r
1624 INTN SkipValue;\r
1625 INTN Difference;\r
1626 INTN OldSkipValue;\r
1627 UINTN DistanceValue;\r
1628 UINTN Row;\r
1629 UINTN Col;\r
1630 UINTN Temp;\r
1631 UINTN Temp2;\r
1632 UINTN TopRow;\r
1633 UINTN BottomRow;\r
1634 UINTN OriginalRow;\r
1635 UINTN Index;\r
1636 UINT32 Count;\r
1637 UINT16 Width;\r
1638 CHAR16 *StringPtr;\r
1639 CHAR16 *OptionString;\r
1640 CHAR16 *OutputString;\r
1641 CHAR16 *FormattedString;\r
1642 CHAR16 YesResponse;\r
1643 CHAR16 NoResponse;\r
1644 BOOLEAN NewLine;\r
1645 BOOLEAN Repaint;\r
1646 BOOLEAN SavedValue;\r
ce6d12cc 1647 BOOLEAN UpArrow;\r
1648 BOOLEAN DownArrow;\r
7936fb6a 1649 EFI_STATUS Status;\r
1650 EFI_INPUT_KEY Key;\r
1651 LIST_ENTRY *Link;\r
1652 LIST_ENTRY *NewPos;\r
1653 LIST_ENTRY *TopOfScreen;\r
1654 LIST_ENTRY *SavedListEntry;\r
1655 UI_MENU_OPTION *MenuOption;\r
1656 UI_MENU_OPTION *NextMenuOption;\r
1657 UI_MENU_OPTION *SavedMenuOption;\r
1658 UI_MENU_OPTION *PreviousMenuOption;\r
1659 UI_CONTROL_FLAG ControlFlag;\r
1660 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
1661 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
1662 UI_SCREEN_OPERATION ScreenOperation;\r
1663 UINT8 MinRefreshInterval;\r
1664 UINTN BufferSize;\r
1665 UINT16 DefaultId;\r
1666 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1667 FORM_BROWSER_STATEMENT *Statement;\r
63d55bb9
LG
1668 CHAR16 TemStr[2];\r
1669 UINT8 *DevicePathBuffer;\r
1670 UINT8 DigitUint8;\r
d66e6c16 1671 UI_MENU_LIST *CurrentMenu;\r
1672 UI_MENU_LIST *MenuList;\r
0c66bc76 1673 FORM_BROWSER_FORM *RefForm;\r
7936fb6a 1674\r
1675 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1676\r
1677 Status = EFI_SUCCESS;\r
1678 FormattedString = NULL;\r
1679 OptionString = NULL;\r
1680 ScreenOperation = UiNoOperation;\r
1681 NewLine = TRUE;\r
1682 MinRefreshInterval = 0;\r
1683 DefaultId = 0;\r
1684\r
1685 OutputString = NULL;\r
ce6d12cc 1686 UpArrow = FALSE;\r
1687 DownArrow = FALSE;\r
7936fb6a 1688 SkipValue = 0;\r
1689 OldSkipValue = 0;\r
1690 MenuRefreshEntry = gMenuRefreshHead;\r
1691\r
1692 NextMenuOption = NULL;\r
1693 PreviousMenuOption = NULL;\r
1694 SavedMenuOption = NULL;\r
0c66bc76 1695 RefForm = NULL;\r
7936fb6a 1696\r
1697 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1698\r
40245175 1699 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE){\r
7936fb6a 1700 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1701 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1702 } else {\r
1703 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1704 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1705 }\r
1706\r
512122dc 1707 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
7936fb6a 1708 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1709\r
1710 Selection->TopRow = TopRow;\r
1711 Selection->BottomRow = BottomRow;\r
1712 Selection->PromptCol = Col;\r
1713 Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1714 Selection->Statement = NULL;\r
1715\r
ce6d12cc 1716 TopOfScreen = gMenuOption.ForwardLink;\r
7936fb6a 1717 Repaint = TRUE;\r
1718 MenuOption = NULL;\r
1719\r
d66e6c16 1720 //\r
1721 // Find current Menu\r
1722 //\r
1723 CurrentMenu = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
1724 if (CurrentMenu == NULL) {\r
1725 //\r
1726 // Current menu not found, add it to the menu tree\r
1727 //\r
1728 CurrentMenu = UiAddMenuList (NULL, &Selection->FormSetGuid, Selection->FormId);\r
1729 }\r
1730 ASSERT (CurrentMenu != NULL);\r
1731\r
1732 if (Selection->QuestionId == 0) {\r
1733 //\r
1734 // Highlight not specified, fetch it from cached menu\r
1735 //\r
1736 Selection->QuestionId = CurrentMenu->QuestionId;\r
1737 }\r
1738\r
7936fb6a 1739 //\r
1740 // Get user's selection\r
1741 //\r
ce6d12cc 1742 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 1743\r
1744 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1745 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1746\r
1747 ControlFlag = CfInitialization;\r
1748 Selection->Action = UI_ACTION_NONE;\r
1749 while (TRUE) {\r
1750 switch (ControlFlag) {\r
1751 case CfInitialization:\r
ce6d12cc 1752 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 1753 ControlFlag = CfReadKey;\r
1754 } else {\r
1755 ControlFlag = CfCheckSelection;\r
1756 }\r
1757 break;\r
1758\r
1759 case CfCheckSelection:\r
1760 if (Selection->Action != UI_ACTION_NONE) {\r
1761 ControlFlag = CfExit;\r
1762 } else {\r
1763 ControlFlag = CfRepaint;\r
1764 }\r
1765 break;\r
1766\r
1767 case CfRepaint:\r
1768 ControlFlag = CfRefreshHighLight;\r
1769\r
1770 if (Repaint) {\r
1771 //\r
1772 // Display menu\r
1773 //\r
ce6d12cc 1774 DownArrow = FALSE;\r
1775 UpArrow = FALSE;\r
7936fb6a 1776 Row = TopRow;\r
1777\r
cd7bfc2c
ED
1778 Temp = (UINTN) SkipValue;\r
1779 Temp2 = (UINTN) SkipValue;\r
7936fb6a 1780\r
1781 ClearLines (\r
1782 LocalScreen.LeftColumn,\r
1783 LocalScreen.RightColumn,\r
1784 TopRow - SCROLL_ARROW_HEIGHT,\r
1785 BottomRow + SCROLL_ARROW_HEIGHT,\r
1786 FIELD_TEXT | FIELD_BACKGROUND\r
1787 );\r
1788\r
1789 UiFreeRefreshList ();\r
1790 MinRefreshInterval = 0;\r
1791\r
ce6d12cc 1792 for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
7936fb6a 1793 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
1794 MenuOption->Row = Row;\r
1795 MenuOption->Col = Col;\r
1796 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1797\r
1798 Statement = MenuOption->ThisTag;\r
1799 if (Statement->InSubtitle) {\r
1800 MenuOption->Col += SUBTITLE_INDENT;\r
1801 }\r
1802\r
1803 if (MenuOption->GrayOut) {\r
1804 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1805 } else {\r
1806 if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
1807 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1808 }\r
1809 }\r
1810\r
1811 Width = GetWidth (Statement, MenuOption->Handle);\r
1812 OriginalRow = Row;\r
1813\r
a605dfb3
LG
1814 if (Statement->Operand == EFI_IFR_REF_OP && ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP)) {\r
1815 //\r
1816 // Print Arrow for Goto button.\r
1817 //\r
1818 PrintAt (\r
1819 MenuOption->Col - LEFT_SKIPPED_COLUMNS,\r
1820 Row,\r
1821 L"%c",\r
1822 GEOMETRICSHAPE_RIGHT_TRIANGLE\r
1823 );\r
1824 }\r
1825\r
7936fb6a 1826 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1827 if ((Temp == 0) && (Row <= BottomRow)) {\r
1828 PrintStringAt (MenuOption->Col, Row, OutputString);\r
1829 }\r
1830 //\r
1831 // If there is more string to process print on the next row and increment the Skip value\r
1832 //\r
d1a54e2c 1833 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 1834 if (Temp == 0) {\r
1835 Row++;\r
1836 }\r
1837 }\r
1838\r
f4113e1f 1839 FreePool (OutputString);\r
7936fb6a 1840 if (Temp != 0) {\r
1841 Temp--;\r
1842 }\r
1843 }\r
1844\r
1845 Temp = 0;\r
1846 Row = OriginalRow;\r
1847\r
8d00a0f1 1848 Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1849 if (EFI_ERROR (Status)) {\r
1850 //\r
1851 // Repaint to clear possible error prompt pop-up\r
1852 //\r
1853 Repaint = TRUE;\r
1854 NewLine = TRUE;\r
1855 ControlFlag = CfRepaint;\r
1856 break;\r
1857 }\r
7936fb6a 1858\r
1859 if (OptionString != NULL) {\r
1860 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
1861 //\r
1862 // If leading spaces on OptionString - remove the spaces\r
1863 //\r
1864 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1865 MenuOption->OptCol++;\r
1866 }\r
1867\r
1868 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1869 OptionString[Count] = OptionString[Index];\r
1870 Count++;\r
1871 }\r
1872\r
1873 OptionString[Count] = CHAR_NULL;\r
1874 }\r
1875\r
1876 //\r
1877 // If Question request refresh, register the op-code\r
1878 //\r
1879 if (Statement->RefreshInterval != 0) {\r
1880 //\r
1881 // Menu will be refreshed at minimal interval of all Questions\r
1882 // which have refresh request\r
1883 //\r
1884 if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
1885 MinRefreshInterval = Statement->RefreshInterval;\r
1886 }\r
1887\r
1888 if (gMenuRefreshHead == NULL) {\r
1889 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1890 ASSERT (MenuRefreshEntry != NULL);\r
1891 MenuRefreshEntry->MenuOption = MenuOption;\r
1892 MenuRefreshEntry->Selection = Selection;\r
1893 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1894 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1895 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1896 gMenuRefreshHead = MenuRefreshEntry;\r
1897 } else {\r
1898 //\r
1899 // Advance to the last entry\r
1900 //\r
1901 for (MenuRefreshEntry = gMenuRefreshHead;\r
1902 MenuRefreshEntry->Next != NULL;\r
1903 MenuRefreshEntry = MenuRefreshEntry->Next\r
1904 )\r
1905 ;\r
1906 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1907 ASSERT (MenuRefreshEntry->Next != NULL);\r
1908 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1909 MenuRefreshEntry->MenuOption = MenuOption;\r
1910 MenuRefreshEntry->Selection = Selection;\r
1911 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1912 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1913 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1914 }\r
1915 }\r
1916\r
1917 Width = (UINT16) gOptionBlockWidth;\r
1918 OriginalRow = Row;\r
1919\r
1920 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1921 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1922 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1923 }\r
1924 //\r
1925 // If there is more string to process print on the next row and increment the Skip value\r
1926 //\r
d1a54e2c 1927 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 1928 if (Temp2 == 0) {\r
1929 Row++;\r
1930 //\r
1931 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1932 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1933 // some testing to ensure we are keeping this in-sync.\r
1934 //\r
1935 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1936 //\r
1937 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1938 MenuOption->Skip++;\r
1939 }\r
1940 }\r
1941 }\r
1942\r
f4113e1f 1943 FreePool (OutputString);\r
7936fb6a 1944 if (Temp2 != 0) {\r
1945 Temp2--;\r
1946 }\r
1947 }\r
1948\r
1949 Temp2 = 0;\r
1950 Row = OriginalRow;\r
1951\r
f4113e1f 1952 FreePool (OptionString);\r
7936fb6a 1953 }\r
1954 //\r
1955 // If this is a text op with secondary text information\r
1956 //\r
1957 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
1958 StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
1959\r
1960 Width = (UINT16) gOptionBlockWidth;\r
1961 OriginalRow = Row;\r
1962\r
1963 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1964 if ((Temp == 0) && (Row <= BottomRow)) {\r
1965 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1966 }\r
1967 //\r
1968 // If there is more string to process print on the next row and increment the Skip value\r
1969 //\r
d1a54e2c 1970 if (StrLen (&StringPtr[Index]) != 0) {\r
7936fb6a 1971 if (Temp2 == 0) {\r
1972 Row++;\r
1973 //\r
1974 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1975 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1976 // some testing to ensure we are keeping this in-sync.\r
1977 //\r
1978 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1979 //\r
1980 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1981 MenuOption->Skip++;\r
1982 }\r
1983 }\r
1984 }\r
1985\r
f4113e1f 1986 FreePool (OutputString);\r
7936fb6a 1987 if (Temp2 != 0) {\r
1988 Temp2--;\r
1989 }\r
1990 }\r
1991\r
1992 Row = OriginalRow;\r
f4113e1f 1993 FreePool (StringPtr);\r
7936fb6a 1994 }\r
1a788cdd 1995 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
7936fb6a 1996\r
1997 //\r
1998 // Need to handle the bottom of the display\r
1999 //\r
2000 if (MenuOption->Skip > 1) {\r
2001 Row += MenuOption->Skip - SkipValue;\r
2002 SkipValue = 0;\r
2003 } else {\r
2004 Row += MenuOption->Skip;\r
2005 }\r
2006\r
2007 if (Row > BottomRow) {\r
2008 if (!ValueIsScroll (FALSE, Link)) {\r
ce6d12cc 2009 DownArrow = TRUE;\r
7936fb6a 2010 }\r
2011\r
2012 Row = BottomRow + 1;\r
2013 break;\r
2014 }\r
2015 }\r
2016\r
2017 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
ce6d12cc 2018 UpArrow = TRUE;\r
7936fb6a 2019 }\r
2020\r
ce6d12cc 2021 if (UpArrow) {\r
7936fb6a 2022 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2023 PrintAt (\r
2024 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2025 TopRow - SCROLL_ARROW_HEIGHT,\r
2026 L"%c",\r
2027 ARROW_UP\r
2028 );\r
2029 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2030 }\r
2031\r
ce6d12cc 2032 if (DownArrow) {\r
7936fb6a 2033 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2034 PrintAt (\r
2035 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2036 BottomRow + SCROLL_ARROW_HEIGHT,\r
2037 L"%c",\r
2038 ARROW_DOWN\r
2039 );\r
2040 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2041 }\r
2042\r
2043 MenuOption = NULL;\r
2044 }\r
2045 break;\r
2046\r
2047 case CfRefreshHighLight:\r
2048 //\r
2049 // MenuOption: Last menu option that need to remove hilight\r
2050 // MenuOption is set to NULL in Repaint\r
2051 // NewPos: Current menu option that need to hilight\r
2052 //\r
2053 ControlFlag = CfUpdateHelpString;\r
2054\r
2055 //\r
2056 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
2057 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
2058 //\r
2059 SavedValue = Repaint;\r
2060 Repaint = FALSE;\r
2061\r
2062 if (Selection->QuestionId != 0) {\r
ce6d12cc 2063 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 2064 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2065\r
ce6d12cc 2066 while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &gMenuOption) {\r
7936fb6a 2067 NewPos = NewPos->ForwardLink;\r
2068 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2069 }\r
2070 if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
2071 //\r
2072 // Target Question found, find its MenuOption\r
2073 //\r
2074 Link = TopOfScreen;\r
2075\r
2076 for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
2077 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2078 Index += SavedMenuOption->Skip;\r
2079 Link = Link->ForwardLink;\r
2080 }\r
2081\r
2082 if (Link != NewPos || Index > BottomRow) {\r
2083 //\r
2084 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
2085 //\r
2086 Link = NewPos;\r
2087 for (Index = TopRow; Index <= BottomRow; ) {\r
2088 Link = Link->BackLink;\r
2089 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2090 Index += SavedMenuOption->Skip;\r
2091 }\r
2092 TopOfScreen = Link->ForwardLink;\r
2093\r
2094 Repaint = TRUE;\r
2095 NewLine = TRUE;\r
2096 ControlFlag = CfRepaint;\r
2097 break;\r
2098 }\r
2099 } else {\r
2100 //\r
2101 // Target Question not found, highlight the default menu option\r
2102 //\r
2103 NewPos = TopOfScreen;\r
2104 }\r
2105\r
2106 Selection->QuestionId = 0;\r
2107 }\r
2108\r
2109 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2110 if (MenuOption != NULL) {\r
2111 //\r
2112 // Remove highlight on last Menu Option\r
2113 //\r
2114 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2115 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2116 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2117 if (OptionString != NULL) {\r
2118 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2119 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2120 ) {\r
2121 //\r
2122 // If leading spaces on OptionString - remove the spaces\r
2123 //\r
2124 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2125 ;\r
2126\r
2127 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2128 OptionString[Count] = OptionString[Index];\r
2129 Count++;\r
2130 }\r
2131\r
2132 OptionString[Count] = CHAR_NULL;\r
2133 }\r
2134\r
2135 Width = (UINT16) gOptionBlockWidth;\r
2136 OriginalRow = MenuOption->Row;\r
2137\r
2138 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2139 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2140 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2141 }\r
2142 //\r
2143 // If there is more string to process print on the next row and increment the Skip value\r
2144 //\r
d1a54e2c 2145 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2146 MenuOption->Row++;\r
2147 }\r
2148\r
f4113e1f 2149 FreePool (OutputString);\r
7936fb6a 2150 }\r
2151\r
2152 MenuOption->Row = OriginalRow;\r
2153\r
f4113e1f 2154 FreePool (OptionString);\r
7936fb6a 2155 } else {\r
2156 if (NewLine) {\r
2157 if (MenuOption->GrayOut) {\r
2158 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2159 } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
2160 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
2161 }\r
2162\r
2163 OriginalRow = MenuOption->Row;\r
2164 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
2165\r
2166 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2167 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2168 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2169 }\r
2170 //\r
2171 // If there is more string to process print on the next row and increment the Skip value\r
2172 //\r
d1a54e2c 2173 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2174 MenuOption->Row++;\r
2175 }\r
2176\r
f4113e1f 2177 FreePool (OutputString);\r
7936fb6a 2178 }\r
2179\r
2180 MenuOption->Row = OriginalRow;\r
2181 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2182 }\r
2183 }\r
2184 }\r
2185\r
2186 //\r
2187 // This is only possible if we entered this page and the first menu option is\r
2188 // a "non-menu" item. In that case, force it UiDown\r
2189 //\r
2190 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2191 if (!IsSelectable (MenuOption)) {\r
2192 ASSERT (ScreenOperation == UiNoOperation);\r
2193 ScreenOperation = UiDown;\r
2194 ControlFlag = CfScreenOperation;\r
2195 break;\r
2196 }\r
2197\r
2198 //\r
2199 // This is the current selected statement\r
2200 //\r
2201 Statement = MenuOption->ThisTag;\r
2202 Selection->Statement = Statement;\r
d66e6c16 2203 //\r
2204 // Record highlight for current menu\r
2205 //\r
2206 CurrentMenu->QuestionId = Statement->QuestionId;\r
7936fb6a 2207\r
2208 //\r
2209 // Set reverse attribute\r
2210 //\r
2211 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
2212 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2213\r
2214 //\r
2215 // Assuming that we have a refresh linked-list created, lets annotate the\r
2216 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
2217 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
2218 //\r
2219 if (gMenuRefreshHead != NULL) {\r
2220 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
2221 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
2222 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
2223 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
2224 }\r
2225 }\r
2226 }\r
2227\r
2228 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2229 if (OptionString != NULL) {\r
2230 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
2231 //\r
2232 // If leading spaces on OptionString - remove the spaces\r
2233 //\r
2234 for (Index = 0; OptionString[Index] == L' '; Index++)\r
2235 ;\r
2236\r
2237 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
2238 OptionString[Count] = OptionString[Index];\r
2239 Count++;\r
2240 }\r
2241\r
2242 OptionString[Count] = CHAR_NULL;\r
2243 }\r
2244 Width = (UINT16) gOptionBlockWidth;\r
2245\r
2246 OriginalRow = MenuOption->Row;\r
2247\r
2248 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2249 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2250 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2251 }\r
2252 //\r
2253 // If there is more string to process print on the next row and increment the Skip value\r
2254 //\r
d1a54e2c 2255 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2256 MenuOption->Row++;\r
2257 }\r
2258\r
f4113e1f 2259 FreePool (OutputString);\r
7936fb6a 2260 }\r
2261\r
2262 MenuOption->Row = OriginalRow;\r
2263\r
f4113e1f 2264 FreePool (OptionString);\r
7936fb6a 2265 } else {\r
2266 if (NewLine) {\r
2267 OriginalRow = MenuOption->Row;\r
2268\r
2269 Width = GetWidth (Statement, MenuOption->Handle);\r
2270\r
2271 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2272 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2273 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2274 }\r
2275 //\r
2276 // If there is more string to process print on the next row and increment the Skip value\r
2277 //\r
d1a54e2c 2278 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2279 MenuOption->Row++;\r
2280 }\r
2281\r
f4113e1f 2282 FreePool (OutputString);\r
7936fb6a 2283 }\r
2284\r
2285 MenuOption->Row = OriginalRow;\r
2286\r
2287 }\r
2288 }\r
2289\r
8b0fc5c1 2290 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
8d00a0f1 2291\r
7936fb6a 2292 //\r
2293 // Clear reverse attribute\r
2294 //\r
2295 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2296 }\r
2297 //\r
2298 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2299 // if we didn't break halfway when process CfRefreshHighLight.\r
2300 //\r
2301 Repaint = SavedValue;\r
2302 break;\r
2303\r
2304 case CfUpdateHelpString:\r
2305 ControlFlag = CfPrepareToReadKey;\r
2306\r
0a1147ed 2307 if (Repaint || NewLine) {\r
7936fb6a 2308 //\r
2309 // Don't print anything if it is a NULL help token\r
2310 //\r
c9325700 2311 ASSERT(MenuOption != NULL);\r
7936fb6a 2312 if (MenuOption->ThisTag->Help == 0) {\r
2313 StringPtr = L"\0";\r
2314 } else {\r
2315 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2316 }\r
2317\r
2318 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2319\r
2320 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2321\r
2322 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2323 //\r
2324 // Pad String with spaces to simulate a clearing of the previous line\r
2325 //\r
2326 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
2327 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");\r
2328 }\r
2329\r
2330 PrintStringAt (\r
2331 LocalScreen.RightColumn - gHelpBlockWidth,\r
2332 Index + TopRow,\r
2333 &FormattedString[Index * gHelpBlockWidth * 2]\r
2334 );\r
2335 }\r
2336 }\r
2337 //\r
2338 // Reset this flag every time we finish using it.\r
2339 //\r
2340 Repaint = FALSE;\r
2341 NewLine = FALSE;\r
2342 break;\r
2343\r
2344 case CfPrepareToReadKey:\r
2345 ControlFlag = CfReadKey;\r
2346 ScreenOperation = UiNoOperation;\r
2347 break;\r
2348\r
2349 case CfReadKey:\r
2350 ControlFlag = CfScreenOperation;\r
2351\r
2352 //\r
2353 // Wait for user's selection\r
2354 //\r
2355 do {\r
2356 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
2357 } while (Status == EFI_TIMEOUT);\r
2358\r
8d00a0f1 2359 if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
7936fb6a 2360 //\r
8d00a0f1 2361 // IFR is updated in Callback of refresh opcode, re-parse it\r
7936fb6a 2362 //\r
8d00a0f1 2363 Selection->Statement = NULL;\r
d66e6c16 2364 return EFI_SUCCESS;\r
8d00a0f1 2365 }\r
2366\r
2367 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2368 //\r
d66e6c16 2369 // If we encounter error, continue to read another key in.\r
8d00a0f1 2370 //\r
2371 if (EFI_ERROR (Status)) {\r
2372 ControlFlag = CfReadKey;\r
2373 break;\r
7936fb6a 2374 }\r
2375\r
7936fb6a 2376 switch (Key.UnicodeChar) {\r
2377 case CHAR_CARRIAGE_RETURN:\r
2378 ScreenOperation = UiSelect;\r
2379 gDirection = 0;\r
2380 break;\r
2381\r
2382 //\r
2383 // We will push the adjustment of these numeric values directly to the input handler\r
2384 // NOTE: we won't handle manual input numeric\r
2385 //\r
2386 case '+':\r
2387 case '-':\r
c9325700
ED
2388 //\r
2389 // If the screen has no menu items, and the user didn't select UiReset\r
2390 // ignore the selection and go back to reading keys.\r
2391 //\r
2392 if(IsListEmpty (&gMenuOption)) {\r
2393 ControlFlag = CfReadKey;\r
2394 break;\r
2395 }\r
2396\r
2397 ASSERT(MenuOption != NULL);\r
7936fb6a 2398 Statement = MenuOption->ThisTag;\r
2399 if ((Statement->Operand == EFI_IFR_DATE_OP)\r
2400 || (Statement->Operand == EFI_IFR_TIME_OP)\r
2401 || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
2402 ){\r
2403 if (Key.UnicodeChar == '+') {\r
2404 gDirection = SCAN_RIGHT;\r
2405 } else {\r
2406 gDirection = SCAN_LEFT;\r
2407 }\r
2408 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
8d00a0f1 2409 if (EFI_ERROR (Status)) {\r
2410 //\r
2411 // Repaint to clear possible error prompt pop-up\r
2412 //\r
2413 Repaint = TRUE;\r
2414 NewLine = TRUE;\r
2415 }\r
676df92c 2416 if (OptionString != NULL) {\r
2417 FreePool (OptionString);\r
2418 }\r
7936fb6a 2419 }\r
2420 break;\r
2421\r
2422 case '^':\r
2423 ScreenOperation = UiUp;\r
2424 break;\r
2425\r
2426 case 'V':\r
2427 case 'v':\r
2428 ScreenOperation = UiDown;\r
2429 break;\r
2430\r
2431 case ' ':\r
40245175 2432 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
c9325700
ED
2433 //\r
2434 // If the screen has no menu items, and the user didn't select UiReset\r
2435 // ignore the selection and go back to reading keys.\r
2436 //\r
2437 if(IsListEmpty (&gMenuOption)) {\r
2438 ControlFlag = CfReadKey;\r
2439 break;\r
2440 }\r
2441 \r
2442 ASSERT(MenuOption != NULL);\r
7936fb6a 2443 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
2444 ScreenOperation = UiSelect;\r
2445 }\r
2446 }\r
2447 break;\r
2448\r
2449 case CHAR_NULL:\r
8b0fc5c1 2450 if (((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
7936fb6a 2451 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2452 ) {\r
2453 //\r
2454 // If the function key has been disabled, just ignore the key.\r
2455 //\r
2456 } else {\r
2457 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2458 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2459 if (Key.ScanCode == SCAN_F9) {\r
2460 //\r
2461 // Reset to standard default\r
2462 //\r
2463 DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
2464 }\r
2465 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2466 break;\r
2467 }\r
2468 }\r
2469 }\r
2470 break;\r
2471 }\r
2472 break;\r
2473\r
2474 case CfScreenOperation:\r
d66e6c16 2475 if (ScreenOperation != UiReset) {\r
7936fb6a 2476 //\r
d66e6c16 2477 // If the screen has no menu items, and the user didn't select UiReset\r
7936fb6a 2478 // ignore the selection and go back to reading keys.\r
2479 //\r
ce6d12cc 2480 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 2481 ControlFlag = CfReadKey;\r
2482 break;\r
2483 }\r
2484 //\r
2485 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2486 //\r
ce6d12cc 2487 for (Link = gMenuOption.ForwardLink; Link != &gMenuOption; Link = Link->ForwardLink) {\r
7936fb6a 2488 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2489 if (IsSelectable (NextMenuOption)) {\r
2490 break;\r
2491 }\r
2492 }\r
2493\r
ce6d12cc 2494 if (Link == &gMenuOption) {\r
7936fb6a 2495 ControlFlag = CfPrepareToReadKey;\r
2496 break;\r
2497 }\r
7936fb6a 2498 }\r
2499\r
2500 for (Index = 0;\r
2501 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2502 Index++\r
2503 ) {\r
2504 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2505 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2506 break;\r
2507 }\r
2508 }\r
2509 break;\r
2510\r
7936fb6a 2511 case CfUiSelect:\r
2512 ControlFlag = CfCheckSelection;\r
2513\r
c9325700 2514 ASSERT(MenuOption != NULL);\r
7936fb6a 2515 Statement = MenuOption->ThisTag;\r
2516 if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
2517 (Statement->Operand == EFI_IFR_DATE_OP) ||\r
2518 (Statement->Operand == EFI_IFR_TIME_OP) ||\r
2519 (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
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
3168 }\r
3169 break;\r
3170\r
3171 case CfUiNoOperation:\r
3172 ControlFlag = CfCheckSelection;\r
3173 break;\r
3174\r
3175 case CfExit:\r
3176 UiFreeRefreshList ();\r
3177\r
3178 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
3179 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3180 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3181 gST->ConOut->OutputString (gST->ConOut, L"\n");\r
3182\r
3183 return EFI_SUCCESS;\r
3184\r
3185 default:\r
3186 break;\r
3187 }\r
3188 }\r
3189}\r