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