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