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