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