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