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