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