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