]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
EDK II Packages: Add Contributions.txt and License.txt files
[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
ba46ab94
ED
2093 CHAR16 *HelpString;\r
2094 CHAR16 *HelpHeaderString;\r
2095 CHAR16 *HelpBottomString;\r
7936fb6a 2096 BOOLEAN NewLine;\r
2097 BOOLEAN Repaint;\r
2098 BOOLEAN SavedValue;\r
ce6d12cc 2099 BOOLEAN UpArrow;\r
2100 BOOLEAN DownArrow;\r
11232773 2101 BOOLEAN InitializedFlag;\r
7936fb6a 2102 EFI_STATUS Status;\r
2103 EFI_INPUT_KEY Key;\r
2104 LIST_ENTRY *Link;\r
2105 LIST_ENTRY *NewPos;\r
2106 LIST_ENTRY *TopOfScreen;\r
2107 LIST_ENTRY *SavedListEntry;\r
2108 UI_MENU_OPTION *MenuOption;\r
2109 UI_MENU_OPTION *NextMenuOption;\r
2110 UI_MENU_OPTION *SavedMenuOption;\r
2111 UI_MENU_OPTION *PreviousMenuOption;\r
2112 UI_CONTROL_FLAG ControlFlag;\r
2113 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
2114 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
211cc6e5 2115 MENU_REFRESH_ENTRY *MenuUpdateEntry; \r
7936fb6a 2116 UI_SCREEN_OPERATION ScreenOperation;\r
2117 UINT8 MinRefreshInterval;\r
7936fb6a 2118 UINT16 DefaultId;\r
7936fb6a 2119 FORM_BROWSER_STATEMENT *Statement;\r
d66e6c16 2120 UI_MENU_LIST *CurrentMenu;\r
b00964a9 2121 UINTN ModalSkipColumn;\r
48a9d5f7 2122 BROWSER_HOT_KEY *HotKey;\r
ba46ab94
ED
2123 UINTN HelpPageIndex;\r
2124 UINTN HelpPageCount;\r
2125 UINTN RowCount;\r
2126 UINTN HelpLine;\r
2127 UINTN HelpHeaderLine;\r
2128 UINTN HelpBottomLine;\r
2129 BOOLEAN MultiHelpPage;\r
7936fb6a 2130\r
2131 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
2132\r
2133 Status = EFI_SUCCESS;\r
ba46ab94
ED
2134 HelpString = NULL;\r
2135 HelpHeaderString = NULL;\r
2136 HelpBottomString = NULL;\r
7936fb6a 2137 OptionString = NULL;\r
2138 ScreenOperation = UiNoOperation;\r
2139 NewLine = TRUE;\r
2140 MinRefreshInterval = 0;\r
2141 DefaultId = 0;\r
ba46ab94
ED
2142 HelpPageCount = 0;\r
2143 HelpLine = 0;\r
2144 RowCount = 0;\r
2145 HelpBottomLine = 0;\r
2146 HelpHeaderLine = 0;\r
2147 HelpPageIndex = 0;\r
2148 MultiHelpPage = FALSE;\r
7936fb6a 2149\r
2150 OutputString = NULL;\r
ce6d12cc 2151 UpArrow = FALSE;\r
2152 DownArrow = FALSE;\r
7936fb6a 2153 SkipValue = 0;\r
2154 OldSkipValue = 0;\r
2155 MenuRefreshEntry = gMenuRefreshHead;\r
2156\r
2157 NextMenuOption = NULL;\r
2158 PreviousMenuOption = NULL;\r
2159 SavedMenuOption = NULL;\r
48a9d5f7 2160 HotKey = NULL;\r
b00964a9 2161 ModalSkipColumn = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6;\r
7936fb6a 2162\r
2163 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
2164\r
40245175 2165 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE){\r
7936fb6a 2166 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2167 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2168 } else {\r
2169 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2170 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2171 }\r
2172\r
b00964a9
ED
2173 if (Selection->Form->ModalForm) {\r
2174 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
2175 } else {\r
2176 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
2177 }\r
2178\r
48a9d5f7 2179 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1;\r
7936fb6a 2180\r
2181 Selection->TopRow = TopRow;\r
2182 Selection->BottomRow = BottomRow;\r
2183 Selection->PromptCol = Col;\r
2184 Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
2185 Selection->Statement = NULL;\r
2186\r
ce6d12cc 2187 TopOfScreen = gMenuOption.ForwardLink;\r
7936fb6a 2188 Repaint = TRUE;\r
2189 MenuOption = NULL;\r
2190\r
d66e6c16 2191 //\r
2192 // Find current Menu\r
2193 //\r
2194 CurrentMenu = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
2195 if (CurrentMenu == NULL) {\r
2196 //\r
2197 // Current menu not found, add it to the menu tree\r
2198 //\r
b2e444aa 2199 CurrentMenu = UiAddMenuList (NULL, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
d66e6c16 2200 }\r
2201 ASSERT (CurrentMenu != NULL);\r
b18e7050 2202 Selection->CurrentMenu = CurrentMenu;\r
d66e6c16 2203\r
2204 if (Selection->QuestionId == 0) {\r
2205 //\r
2206 // Highlight not specified, fetch it from cached menu\r
2207 //\r
2208 Selection->QuestionId = CurrentMenu->QuestionId;\r
d88ca2c9 2209 Selection->Sequence = CurrentMenu->Sequence;\r
d66e6c16 2210 }\r
2211\r
7936fb6a 2212 //\r
11232773 2213 // Init option as the current user's selection\r
7936fb6a 2214 //\r
11232773 2215 InitializedFlag = TRUE;\r
ce6d12cc 2216 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 2217\r
2218 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
b18e7050 2219 UpdateStatusBar (Selection, REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
7936fb6a 2220\r
2221 ControlFlag = CfInitialization;\r
2222 Selection->Action = UI_ACTION_NONE;\r
2223 while (TRUE) {\r
2224 switch (ControlFlag) {\r
2225 case CfInitialization:\r
ce6d12cc 2226 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 2227 ControlFlag = CfReadKey;\r
2228 } else {\r
2229 ControlFlag = CfCheckSelection;\r
2230 }\r
2231 break;\r
2232\r
2233 case CfCheckSelection:\r
2234 if (Selection->Action != UI_ACTION_NONE) {\r
2235 ControlFlag = CfExit;\r
2236 } else {\r
2237 ControlFlag = CfRepaint;\r
2238 }\r
2239 break;\r
2240\r
2241 case CfRepaint:\r
2242 ControlFlag = CfRefreshHighLight;\r
2243\r
2244 if (Repaint) {\r
2245 //\r
2246 // Display menu\r
2247 //\r
ce6d12cc 2248 DownArrow = FALSE;\r
2249 UpArrow = FALSE;\r
7936fb6a 2250 Row = TopRow;\r
2251\r
cd7bfc2c
ED
2252 Temp = (UINTN) SkipValue;\r
2253 Temp2 = (UINTN) SkipValue;\r
7936fb6a 2254\r
b00964a9
ED
2255 if (Selection->Form->ModalForm) {\r
2256 ClearLines (\r
2257 LocalScreen.LeftColumn + ModalSkipColumn,\r
2258 LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
2259 TopRow - SCROLL_ARROW_HEIGHT,\r
2260 BottomRow + SCROLL_ARROW_HEIGHT,\r
2261 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2262 ); \r
2263 } else {\r
2264 ClearLines (\r
2265 LocalScreen.LeftColumn,\r
2266 LocalScreen.RightColumn,\r
2267 TopRow - SCROLL_ARROW_HEIGHT,\r
2268 BottomRow + SCROLL_ARROW_HEIGHT,\r
2269 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2270 );\r
2271 }\r
7936fb6a 2272 UiFreeRefreshList ();\r
2273 MinRefreshInterval = 0;\r
2274\r
ce6d12cc 2275 for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
7936fb6a 2276 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
2277 MenuOption->Row = Row;\r
2278 MenuOption->Col = Col;\r
b00964a9
ED
2279 if (Selection->Form->ModalForm) {\r
2280 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn;\r
2281 } else {\r
2282 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
2283 }\r
7936fb6a 2284\r
2285 Statement = MenuOption->ThisTag;\r
2286 if (Statement->InSubtitle) {\r
2287 MenuOption->Col += SUBTITLE_INDENT;\r
2288 }\r
2289\r
2290 if (MenuOption->GrayOut) {\r
2291 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2292 } else {\r
2293 if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
f0a1bf11 2294 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2295 }\r
2296 }\r
2297\r
2298 Width = GetWidth (Statement, MenuOption->Handle);\r
2299 OriginalRow = Row;\r
2300\r
11232773 2301 if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
a605dfb3
LG
2302 //\r
2303 // Print Arrow for Goto button.\r
2304 //\r
2305 PrintAt (\r
b6ca1fd8 2306 MenuOption->Col - 2,\r
a605dfb3
LG
2307 Row,\r
2308 L"%c",\r
2309 GEOMETRICSHAPE_RIGHT_TRIANGLE\r
2310 );\r
2311 }\r
2312\r
7936fb6a 2313 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2314 if ((Temp == 0) && (Row <= BottomRow)) {\r
2315 PrintStringAt (MenuOption->Col, Row, OutputString);\r
2316 }\r
2317 //\r
2318 // If there is more string to process print on the next row and increment the Skip value\r
2319 //\r
d1a54e2c 2320 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2321 if (Temp == 0) {\r
2322 Row++;\r
2323 }\r
2324 }\r
2325\r
f4113e1f 2326 FreePool (OutputString);\r
7936fb6a 2327 if (Temp != 0) {\r
2328 Temp--;\r
2329 }\r
2330 }\r
2331\r
2332 Temp = 0;\r
2333 Row = OriginalRow;\r
2334\r
8d00a0f1 2335 Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2336 if (EFI_ERROR (Status)) {\r
2337 //\r
2338 // Repaint to clear possible error prompt pop-up\r
2339 //\r
2340 Repaint = TRUE;\r
2341 NewLine = TRUE;\r
2342 ControlFlag = CfRepaint;\r
2343 break;\r
2344 }\r
7936fb6a 2345\r
2346 if (OptionString != NULL) {\r
2347 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
4a6876b7 2348 ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
7936fb6a 2349 }\r
2350\r
7936fb6a 2351 Width = (UINT16) gOptionBlockWidth;\r
2352 OriginalRow = Row;\r
2353\r
2354 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2355 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
2356 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
2357 }\r
2358 //\r
2359 // If there is more string to process print on the next row and increment the Skip value\r
2360 //\r
d1a54e2c 2361 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2362 if (Temp2 == 0) {\r
2363 Row++;\r
2364 //\r
2365 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
2366 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
2367 // some testing to ensure we are keeping this in-sync.\r
2368 //\r
2369 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
2370 //\r
2371 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
2372 MenuOption->Skip++;\r
2373 }\r
2374 }\r
2375 }\r
2376\r
f4113e1f 2377 FreePool (OutputString);\r
7936fb6a 2378 if (Temp2 != 0) {\r
2379 Temp2--;\r
2380 }\r
2381 }\r
2382\r
2383 Temp2 = 0;\r
2384 Row = OriginalRow;\r
2385\r
f4113e1f 2386 FreePool (OptionString);\r
7936fb6a 2387 }\r
4ffaadcc
ED
2388\r
2389 //\r
2390 // If Question has refresh guid, register the op-code.\r
2391 //\r
2392 if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
2393 if (gMenuEventGuidRefreshHead == NULL) {\r
2394 MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2395 gMenuEventGuidRefreshHead = MenuUpdateEntry;\r
2396 } else {\r
2397 MenuUpdateEntry = gMenuEventGuidRefreshHead;\r
2398 while (MenuUpdateEntry->Next != NULL) {\r
2399 MenuUpdateEntry = MenuUpdateEntry->Next; \r
2400 }\r
2401 MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2402 MenuUpdateEntry = MenuUpdateEntry->Next; \r
2403 }\r
2404 ASSERT (MenuUpdateEntry != NULL);\r
2405 Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event);\r
2406 ASSERT (!EFI_ERROR (Status));\r
2407 MenuUpdateEntry->MenuOption = MenuOption;\r
2408 MenuUpdateEntry->Selection = Selection;\r
2409 MenuUpdateEntry->CurrentColumn = MenuOption->OptCol;\r
2410 MenuUpdateEntry->CurrentRow = MenuOption->Row;\r
2411 if (MenuOption->GrayOut) {\r
2412 MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2413 } else {\r
2414 MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2415 }\r
2416 }\r
2417 \r
2418 //\r
2419 // If Question request refresh, register the op-code\r
2420 //\r
2421 if (Statement->RefreshInterval != 0) {\r
2422 //\r
2423 // Menu will be refreshed at minimal interval of all Questions\r
2424 // which have refresh request\r
2425 //\r
2426 if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
2427 MinRefreshInterval = Statement->RefreshInterval;\r
2428 }\r
2429 \r
2430 if (gMenuRefreshHead == NULL) {\r
2431 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2432 gMenuRefreshHead = MenuRefreshEntry;\r
2433 } else {\r
2434 MenuRefreshEntry = gMenuRefreshHead;\r
2435 while (MenuRefreshEntry->Next != NULL) {\r
2436 MenuRefreshEntry = MenuRefreshEntry->Next; \r
2437 }\r
2438 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2439 MenuRefreshEntry = MenuRefreshEntry->Next;\r
2440 }\r
2441 ASSERT (MenuRefreshEntry != NULL); \r
2442 MenuRefreshEntry->MenuOption = MenuOption;\r
2443 MenuRefreshEntry->Selection = Selection;\r
2444 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
2445 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
2446 if (MenuOption->GrayOut) {\r
2447 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2448 } else { \r
2449 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2450 }\r
2451 }\r
2452 \r
7936fb6a 2453 //\r
2454 // If this is a text op with secondary text information\r
2455 //\r
2456 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
2457 StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
2458\r
2459 Width = (UINT16) gOptionBlockWidth;\r
2460 OriginalRow = Row;\r
2461\r
2462 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
2463 if ((Temp == 0) && (Row <= BottomRow)) {\r
2464 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
2465 }\r
2466 //\r
2467 // If there is more string to process print on the next row and increment the Skip value\r
2468 //\r
d1a54e2c 2469 if (StrLen (&StringPtr[Index]) != 0) {\r
7936fb6a 2470 if (Temp2 == 0) {\r
2471 Row++;\r
2472 //\r
2473 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
2474 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
2475 // some testing to ensure we are keeping this in-sync.\r
2476 //\r
2477 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
2478 //\r
2479 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
2480 MenuOption->Skip++;\r
2481 }\r
2482 }\r
2483 }\r
2484\r
f4113e1f 2485 FreePool (OutputString);\r
7936fb6a 2486 if (Temp2 != 0) {\r
2487 Temp2--;\r
2488 }\r
2489 }\r
2490\r
2491 Row = OriginalRow;\r
f4113e1f 2492 FreePool (StringPtr);\r
7936fb6a 2493 }\r
f0a1bf11 2494 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2495\r
2496 //\r
2497 // Need to handle the bottom of the display\r
2498 //\r
2499 if (MenuOption->Skip > 1) {\r
2500 Row += MenuOption->Skip - SkipValue;\r
2501 SkipValue = 0;\r
2502 } else {\r
2503 Row += MenuOption->Skip;\r
2504 }\r
2505\r
2506 if (Row > BottomRow) {\r
2507 if (!ValueIsScroll (FALSE, Link)) {\r
ce6d12cc 2508 DownArrow = TRUE;\r
7936fb6a 2509 }\r
2510\r
2511 Row = BottomRow + 1;\r
2512 break;\r
2513 }\r
2514 }\r
2515\r
2516 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
ce6d12cc 2517 UpArrow = TRUE;\r
7936fb6a 2518 }\r
2519\r
ce6d12cc 2520 if (UpArrow) {\r
7936fb6a 2521 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2522 PrintAt (\r
2523 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2524 TopRow - SCROLL_ARROW_HEIGHT,\r
2525 L"%c",\r
2526 ARROW_UP\r
2527 );\r
f0a1bf11 2528 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2529 }\r
2530\r
ce6d12cc 2531 if (DownArrow) {\r
7936fb6a 2532 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2533 PrintAt (\r
2534 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2535 BottomRow + SCROLL_ARROW_HEIGHT,\r
2536 L"%c",\r
2537 ARROW_DOWN\r
2538 );\r
f0a1bf11 2539 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2540 }\r
2541\r
2542 MenuOption = NULL;\r
2543 }\r
2544 break;\r
2545\r
2546 case CfRefreshHighLight:\r
2547 //\r
2548 // MenuOption: Last menu option that need to remove hilight\r
2549 // MenuOption is set to NULL in Repaint\r
2550 // NewPos: Current menu option that need to hilight\r
2551 //\r
2552 ControlFlag = CfUpdateHelpString;\r
11232773
LG
2553 if (InitializedFlag) {\r
2554 InitializedFlag = FALSE;\r
5f4ef94a 2555 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773 2556 }\r
7936fb6a 2557\r
2558 //\r
2559 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
2560 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
2561 //\r
2562 SavedValue = Repaint;\r
2563 Repaint = FALSE;\r
2564\r
2565 if (Selection->QuestionId != 0) {\r
ce6d12cc 2566 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 2567 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2568\r
d88ca2c9
ED
2569 while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId ||\r
2570 SavedMenuOption->Sequence != Selection->Sequence) &&\r
2571 NewPos->ForwardLink != &gMenuOption) {\r
7936fb6a 2572 NewPos = NewPos->ForwardLink;\r
2573 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2574 }\r
2575 if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
2576 //\r
2577 // Target Question found, find its MenuOption\r
2578 //\r
2579 Link = TopOfScreen;\r
2580\r
2581 for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
2582 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2583 Index += SavedMenuOption->Skip;\r
5f4ef94a
ED
2584 if (Link == TopOfScreen) {\r
2585 Index -= OldSkipValue;\r
2586 }\r
7936fb6a 2587 Link = Link->ForwardLink;\r
2588 }\r
5f4ef94a
ED
2589 if (NewPos == Link) {\r
2590 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2591 }\r
7936fb6a 2592\r
08476b33
ED
2593 //\r
2594 // Not find the selected menu in current show page.\r
2595 // Have two case to enter this if:\r
2596 // 1. Not find the menu at current page.\r
2597 // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
2598 // For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
2599 //\r
2600 // Base on the selected menu will show at the bottom of the page,\r
2601 // select the menu which will show at the top of the page.\r
2602 //\r
2603 if (Link != NewPos || Index > BottomRow || \r
2604 (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\r
85aa96cd
ED
2605 //\r
2606 // Find the MenuOption which has the skip value for Date/Time opcode. \r
2607 //\r
2608 AdjustDateAndTimePosition(FALSE, &NewPos);\r
7936fb6a 2609 //\r
2610 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
2611 //\r
5f4ef94a
ED
2612 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2613 //\r
2614 // SavedMenuOption->Row == 0 means the menu not show yet.\r
2615 //\r
2616 if (SavedMenuOption->Row == 0) {\r
2617 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
2618 }\r
08476b33
ED
2619\r
2620 //\r
2621 // Base on the selected menu will show at the bottome of next page, \r
2622 // select the menu show at the top of the next page. \r
2623 //\r
7936fb6a 2624 Link = NewPos;\r
5f4ef94a 2625 for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) { \r
7936fb6a 2626 Link = Link->BackLink;\r
2627 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
5f4ef94a
ED
2628 if (SavedMenuOption->Row == 0) {\r
2629 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
2630 }\r
08476b33 2631 Index += SavedMenuOption->Skip;\r
7936fb6a 2632 }\r
08476b33
ED
2633\r
2634 //\r
2635 // Found the menu which will show at the top of the page.\r
2636 //\r
2637 if (Link == NewPos) {\r
2638 //\r
2639 // The menu can show more than one pages, just show the menu at the top of the page.\r
2640 //\r
2641 SkipValue = 0;\r
2642 TopOfScreen = Link;\r
2643 OldSkipValue = SkipValue;\r
5f4ef94a 2644 } else {\r
08476b33
ED
2645 //\r
2646 // Check whether need to skip some line for menu shows at the top of the page.\r
2647 //\r
2648 SkipValue = Index - BottomRow - 1;\r
2649 if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
2650 TopOfScreen = Link;\r
2651 OldSkipValue = SkipValue;\r
2652 } else {\r
2653 SkipValue = 0;\r
2654 TopOfScreen = Link->ForwardLink;\r
2655 }\r
5f4ef94a 2656 }\r
7936fb6a 2657\r
2658 Repaint = TRUE;\r
2659 NewLine = TRUE;\r
2660 ControlFlag = CfRepaint;\r
2661 break;\r
2662 }\r
2663 } else {\r
2664 //\r
2665 // Target Question not found, highlight the default menu option\r
2666 //\r
2667 NewPos = TopOfScreen;\r
2668 }\r
2669\r
2670 Selection->QuestionId = 0;\r
2671 }\r
2672\r
2673 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2674 if (MenuOption != NULL) {\r
2675 //\r
2676 // Remove highlight on last Menu Option\r
2677 //\r
2678 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2679 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
f0a1bf11 2680 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2681 if (OptionString != NULL) {\r
2682 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2683 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2684 ) {\r
4a6876b7 2685 ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
7936fb6a 2686 }\r
2687\r
2688 Width = (UINT16) gOptionBlockWidth;\r
2689 OriginalRow = MenuOption->Row;\r
2690\r
2691 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2692 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2693 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2694 }\r
2695 //\r
2696 // If there is more string to process print on the next row and increment the Skip value\r
2697 //\r
d1a54e2c 2698 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2699 MenuOption->Row++;\r
2700 }\r
2701\r
f4113e1f 2702 FreePool (OutputString);\r
7936fb6a 2703 }\r
2704\r
2705 MenuOption->Row = OriginalRow;\r
2706\r
f4113e1f 2707 FreePool (OptionString);\r
7936fb6a 2708 } else {\r
2709 if (NewLine) {\r
2710 if (MenuOption->GrayOut) {\r
2711 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2712 } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
f0a1bf11 2713 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2714 }\r
2715\r
2716 OriginalRow = MenuOption->Row;\r
2717 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
2718\r
2719 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2720 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2721 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2722 }\r
2723 //\r
2724 // If there is more string to process print on the next row and increment the Skip value\r
2725 //\r
d1a54e2c 2726 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2727 MenuOption->Row++;\r
2728 }\r
2729\r
f4113e1f 2730 FreePool (OutputString);\r
7936fb6a 2731 }\r
2732\r
2733 MenuOption->Row = OriginalRow;\r
f0a1bf11 2734 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2735 }\r
2736 }\r
2737 }\r
2738\r
2739 //\r
11232773 2740 // This is the current selected statement\r
7936fb6a 2741 //\r
2742 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
11232773
LG
2743 Statement = MenuOption->ThisTag;\r
2744 Selection->Statement = Statement;\r
7936fb6a 2745 if (!IsSelectable (MenuOption)) {\r
11232773
LG
2746 Repaint = SavedValue;\r
2747 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
7936fb6a 2748 break;\r
2749 }\r
2750\r
d66e6c16 2751 //\r
2752 // Record highlight for current menu\r
2753 //\r
2754 CurrentMenu->QuestionId = Statement->QuestionId;\r
d88ca2c9 2755 CurrentMenu->Sequence = MenuOption->Sequence;\r
7936fb6a 2756\r
2757 //\r
2758 // Set reverse attribute\r
2759 //\r
f0a1bf11 2760 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
7936fb6a 2761 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2762\r
2763 //\r
2764 // Assuming that we have a refresh linked-list created, lets annotate the\r
2765 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
2766 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
2767 //\r
2768 if (gMenuRefreshHead != NULL) {\r
2769 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
81da6ef9 2770 if (MenuRefreshEntry->MenuOption->GrayOut) {\r
1fcd34f8
ED
2771 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2772 } else { \r
2773 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2774 }\r
7936fb6a 2775 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
f0a1bf11 2776 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\r
7936fb6a 2777 }\r
2778 }\r
2779 }\r
2780\r
2781 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2782 if (OptionString != NULL) {\r
2783 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
4a6876b7 2784 ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
7936fb6a 2785 }\r
2786 Width = (UINT16) gOptionBlockWidth;\r
2787\r
2788 OriginalRow = MenuOption->Row;\r
2789\r
2790 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2791 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2792 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2793 }\r
2794 //\r
2795 // If there is more string to process print on the next row and increment the Skip value\r
2796 //\r
d1a54e2c 2797 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2798 MenuOption->Row++;\r
2799 }\r
2800\r
f4113e1f 2801 FreePool (OutputString);\r
7936fb6a 2802 }\r
2803\r
2804 MenuOption->Row = OriginalRow;\r
2805\r
f4113e1f 2806 FreePool (OptionString);\r
7936fb6a 2807 } else {\r
2808 if (NewLine) {\r
2809 OriginalRow = MenuOption->Row;\r
2810\r
2811 Width = GetWidth (Statement, MenuOption->Handle);\r
2812\r
2813 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2814 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2815 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2816 }\r
2817 //\r
2818 // If there is more string to process print on the next row and increment the Skip value\r
2819 //\r
d1a54e2c 2820 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2821 MenuOption->Row++;\r
2822 }\r
2823\r
f4113e1f 2824 FreePool (OutputString);\r
7936fb6a 2825 }\r
2826\r
2827 MenuOption->Row = OriginalRow;\r
2828\r
2829 }\r
2830 }\r
2831\r
8b0fc5c1 2832 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
8d00a0f1 2833\r
7936fb6a 2834 //\r
2835 // Clear reverse attribute\r
2836 //\r
f0a1bf11 2837 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2838 }\r
2839 //\r
2840 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2841 // if we didn't break halfway when process CfRefreshHighLight.\r
2842 //\r
2843 Repaint = SavedValue;\r
2844 break;\r
2845\r
2846 case CfUpdateHelpString:\r
2847 ControlFlag = CfPrepareToReadKey;\r
b00964a9
ED
2848 if (Selection->Form->ModalForm) {\r
2849 break;\r
2850 }\r
7936fb6a 2851\r
11232773 2852 if (Repaint || NewLine) {\r
7936fb6a 2853 //\r
2854 // Don't print anything if it is a NULL help token\r
2855 //\r
c9325700 2856 ASSERT(MenuOption != NULL);\r
11232773 2857 if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
7936fb6a 2858 StringPtr = L"\0";\r
2859 } else {\r
2860 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2861 }\r
2862\r
ba46ab94
ED
2863 RowCount = BottomRow - TopRow;\r
2864 HelpPageIndex = 0;\r
2865 //\r
2866 // 1.Calculate how many line the help string need to print.\r
2867 //\r
2868 HelpLine = ProcessHelpString (StringPtr, &HelpString, RowCount);\r
2869 if (HelpLine > RowCount) {\r
2870 MultiHelpPage = TRUE;\r
2871 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
2872 HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, RowCount);\r
2873 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
2874 HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, RowCount);\r
7936fb6a 2875 //\r
ba46ab94 2876 // Calculate the help page count.\r
7936fb6a 2877 //\r
ba46ab94
ED
2878 if (HelpLine > 2 * RowCount - 2) {\r
2879 HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
2880 if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
2881 HelpPageCount += 1;\r
2882 }\r
2883 } else {\r
2884 HelpPageCount = 2;\r
7936fb6a 2885 }\r
ba46ab94
ED
2886 } else {\r
2887 MultiHelpPage = FALSE;\r
2888 }\r
2889 }\r
2890\r
2891 //\r
2892 // Clean the help field first.\r
2893 //\r
2894 ClearLines (\r
2895 LocalScreen.RightColumn - gHelpBlockWidth,\r
2896 LocalScreen.RightColumn,\r
2897 TopRow,\r
2898 BottomRow,\r
2899 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2900 );\r
7936fb6a 2901\r
ba46ab94
ED
2902 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
2903 //\r
2904 // Check whether need to show the 'More(U/u)' at the begin.\r
2905 // Base on current direct info, here shows aligned to the right side of the column.\r
2906 // If the direction is multi line and aligned to right side may have problem, so \r
2907 // add ASSERT code here.\r
2908 //\r
2909 if (HelpPageIndex > 0) {\r
2910 for (Index = 0; Index < HelpHeaderLine; Index++) {\r
2911 ASSERT (HelpHeaderLine == 1);\r
2912 ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
2913 PrintStringAt (\r
2914 LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
2915 Index + TopRow,\r
2916 &HelpHeaderString[Index * gHelpBlockWidth * 2]\r
2917 );\r
2918 }\r
2919 }\r
2920\r
2921 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2922 //\r
2923 // Print the help string info.\r
2924 //\r
2925 if (!MultiHelpPage) {\r
2926 for (Index = 0; Index < RowCount; Index++) {\r
7936fb6a 2927 PrintStringAt (\r
2928 LocalScreen.RightColumn - gHelpBlockWidth,\r
2929 Index + TopRow,\r
ba46ab94
ED
2930 &HelpString[Index * gHelpBlockWidth * 2]\r
2931 );\r
2932 }\r
2933 } else {\r
2934 if (HelpPageIndex == 0) {\r
2935 for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
2936 PrintStringAt (\r
2937 LocalScreen.RightColumn - gHelpBlockWidth,\r
2938 Index + TopRow,\r
2939 &HelpString[Index * gHelpBlockWidth * 2]\r
2940 );\r
2941 }\r
2942 } else {\r
2943 for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
2944 (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
2945 PrintStringAt (\r
2946 LocalScreen.RightColumn - gHelpBlockWidth,\r
2947 Index + TopRow + HelpHeaderLine,\r
2948 &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* gHelpBlockWidth * 2]\r
2949 );\r
2950 }\r
2951 } \r
2952 }\r
2953\r
2954 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
2955 //\r
2956 // Check whether need to print the 'More(D/d)' at the bottom.\r
2957 // Base on current direct info, here shows aligned to the right side of the column.\r
2958 // If the direction is multi line and aligned to right side may have problem, so \r
2959 // add ASSERT code here.\r
2960 //\r
2961 if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
2962 for (Index = 0; Index < HelpBottomLine; Index++) {\r
2963 ASSERT (HelpBottomLine == 1);\r
2964 ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
2965 PrintStringAt (\r
2966 LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
2967 Index + BottomRow - HelpBottomLine,\r
2968 &HelpBottomString[Index * gHelpBlockWidth * 2]\r
7936fb6a 2969 );\r
2970 }\r
2971 }\r
2972 //\r
2973 // Reset this flag every time we finish using it.\r
2974 //\r
2975 Repaint = FALSE;\r
2976 NewLine = FALSE;\r
2977 break;\r
2978\r
2979 case CfPrepareToReadKey:\r
2980 ControlFlag = CfReadKey;\r
2981 ScreenOperation = UiNoOperation;\r
2982 break;\r
2983\r
2984 case CfReadKey:\r
2985 ControlFlag = CfScreenOperation;\r
2986\r
2987 //\r
2988 // Wait for user's selection\r
2989 //\r
2990 do {\r
2991 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
2992 } while (Status == EFI_TIMEOUT);\r
2993\r
8d00a0f1 2994 if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
7936fb6a 2995 //\r
8d00a0f1 2996 // IFR is updated in Callback of refresh opcode, re-parse it\r
7936fb6a 2997 //\r
48a9d5f7 2998 ControlFlag = CfCheckSelection;\r
8d00a0f1 2999 Selection->Statement = NULL;\r
48a9d5f7 3000 break;\r
8d00a0f1 3001 }\r
3002\r
3003 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3004 //\r
d66e6c16 3005 // If we encounter error, continue to read another key in.\r
8d00a0f1 3006 //\r
3007 if (EFI_ERROR (Status)) {\r
3008 ControlFlag = CfReadKey;\r
3009 break;\r
7936fb6a 3010 }\r
3011\r
7936fb6a 3012 switch (Key.UnicodeChar) {\r
3013 case CHAR_CARRIAGE_RETURN:\r
febca2e3
ED
3014 if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
3015 ControlFlag = CfReadKey;\r
3016 break;\r
3017 }\r
3018\r
7936fb6a 3019 ScreenOperation = UiSelect;\r
3020 gDirection = 0;\r
3021 break;\r
3022\r
3023 //\r
3024 // We will push the adjustment of these numeric values directly to the input handler\r
3025 // NOTE: we won't handle manual input numeric\r
3026 //\r
3027 case '+':\r
3028 case '-':\r
c9325700
ED
3029 //\r
3030 // If the screen has no menu items, and the user didn't select UiReset\r
3031 // ignore the selection and go back to reading keys.\r
3032 //\r
febca2e3 3033 if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
c9325700
ED
3034 ControlFlag = CfReadKey;\r
3035 break;\r
3036 }\r
3037\r
3038 ASSERT(MenuOption != NULL);\r
7936fb6a 3039 Statement = MenuOption->ThisTag;\r
3040 if ((Statement->Operand == EFI_IFR_DATE_OP)\r
3041 || (Statement->Operand == EFI_IFR_TIME_OP)\r
3042 || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
3043 ){\r
3044 if (Key.UnicodeChar == '+') {\r
3045 gDirection = SCAN_RIGHT;\r
3046 } else {\r
3047 gDirection = SCAN_LEFT;\r
3048 }\r
3049 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
8d00a0f1 3050 if (EFI_ERROR (Status)) {\r
3051 //\r
3052 // Repaint to clear possible error prompt pop-up\r
3053 //\r
3054 Repaint = TRUE;\r
3055 NewLine = TRUE;\r
7b546f74
ED
3056 } else {\r
3057 Selection->Action = UI_ACTION_REFRESH_FORM;\r
8d00a0f1 3058 }\r
676df92c 3059 if (OptionString != NULL) {\r
3060 FreePool (OptionString);\r
3061 }\r
7936fb6a 3062 }\r
3063 break;\r
3064\r
3065 case '^':\r
3066 ScreenOperation = UiUp;\r
3067 break;\r
3068\r
3069 case 'V':\r
3070 case 'v':\r
3071 ScreenOperation = UiDown;\r
3072 break;\r
3073\r
3074 case ' ':\r
40245175 3075 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
c9325700
ED
3076 //\r
3077 // If the screen has no menu items, and the user didn't select UiReset\r
3078 // ignore the selection and go back to reading keys.\r
3079 //\r
3080 if(IsListEmpty (&gMenuOption)) {\r
3081 ControlFlag = CfReadKey;\r
3082 break;\r
3083 }\r
3084 \r
3085 ASSERT(MenuOption != NULL);\r
febca2e3 3086 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
7936fb6a 3087 ScreenOperation = UiSelect;\r
3088 }\r
3089 }\r
3090 break;\r
3091\r
ba46ab94
ED
3092 case 'D':\r
3093 case 'd':\r
3094 if (!MultiHelpPage) {\r
3095 ControlFlag = CfReadKey;\r
3096 break;\r
3097 }\r
3098 ControlFlag = CfUpdateHelpString;\r
3099 HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
3100 break;\r
3101\r
3102 case 'U':\r
3103 case 'u':\r
3104 if (!MultiHelpPage) {\r
3105 ControlFlag = CfReadKey;\r
3106 break;\r
3107 }\r
3108 ControlFlag = CfUpdateHelpString;\r
3109 HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
3110 break;\r
3111\r
7936fb6a 3112 case CHAR_NULL:\r
48a9d5f7
LG
3113 for (Index = 0; Index < mScanCodeNumber; Index++) {\r
3114 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
3115 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
3116 break;\r
3117 }\r
3118 }\r
3119 \r
3120 if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
7936fb6a 3121 //\r
48a9d5f7 3122 // ModalForm has no ESC key and Hot Key.\r
7936fb6a 3123 //\r
48a9d5f7
LG
3124 ControlFlag = CfReadKey;\r
3125 } else if (Index == mScanCodeNumber) {\r
3126 //\r
3127 // Check whether Key matches the registered hot key.\r
3128 //\r
3129 HotKey = NULL;\r
3130 if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
3131 HotKey = GetHotKeyFromRegisterList (&Key);\r
3132 }\r
3133 if (HotKey != NULL) {\r
3134 ScreenOperation = UiHotKey;\r
7936fb6a 3135 }\r
3136 }\r
3137 break;\r
3138 }\r
3139 break;\r
3140\r
3141 case CfScreenOperation:\r
d66e6c16 3142 if (ScreenOperation != UiReset) {\r
7936fb6a 3143 //\r
d66e6c16 3144 // If the screen has no menu items, and the user didn't select UiReset\r
7936fb6a 3145 // ignore the selection and go back to reading keys.\r
3146 //\r
ce6d12cc 3147 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 3148 ControlFlag = CfReadKey;\r
3149 break;\r
3150 }\r
7936fb6a 3151 }\r
3152\r
3153 for (Index = 0;\r
3154 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
3155 Index++\r
3156 ) {\r
3157 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
3158 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
3159 break;\r
3160 }\r
3161 }\r
3162 break;\r
3163\r
7936fb6a 3164 case CfUiSelect:\r
3165 ControlFlag = CfCheckSelection;\r
3166\r
c9325700 3167 ASSERT(MenuOption != NULL);\r
7936fb6a 3168 Statement = MenuOption->ThisTag;\r
e24adb18 3169 if (Statement->Operand == EFI_IFR_TEXT_OP) {\r
7936fb6a 3170 break;\r
3171 }\r
3172\r
3173 //\r
3174 // Keep highlight on current MenuOption\r
3175 //\r
3176 Selection->QuestionId = Statement->QuestionId;\r
3177\r
3178 switch (Statement->Operand) {\r
3179 case EFI_IFR_REF_OP:\r
8ca6180f 3180 ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
7936fb6a 3181 break;\r
3182\r
3183 case EFI_IFR_ACTION_OP:\r
3184 //\r
3185 // Process the Config string <ConfigResp>\r
3186 //\r
3187 Status = ProcessQuestionConfig (Selection, Statement);\r
3188\r
3189 if (EFI_ERROR (Status)) {\r
3190 break;\r
3191 }\r
3192\r
3193 //\r
3194 // The action button may change some Question value, so refresh the form\r
3195 //\r
3196 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3197 break;\r
3198\r
3199 case EFI_IFR_RESET_BUTTON_OP:\r
3200 //\r
3201 // Reset Question to default value specified by DefaultId\r
3202 //\r
3203 ControlFlag = CfUiDefault;\r
3204 DefaultId = Statement->DefaultId;\r
3205 break;\r
3206\r
3207 default:\r
3208 //\r
3209 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
3210 //\r
8b0fc5c1 3211 UpdateKeyHelp (Selection, MenuOption, TRUE);\r
7936fb6a 3212 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
3213\r
3214 if (EFI_ERROR (Status)) {\r
3215 Repaint = TRUE;\r
3216 NewLine = TRUE;\r
8b0fc5c1 3217 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
3218 } else {\r
3219 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3220 }\r
7936fb6a 3221\r
0c66bc76
LG
3222 if (OptionString != NULL) {\r
3223 FreePool (OptionString);\r
3224 }\r
7936fb6a 3225 break;\r
3226 }\r
3227 break;\r
3228\r
3229 case CfUiReset:\r
3230 //\r
d66e6c16 3231 // We come here when someone press ESC\r
7936fb6a 3232 //\r
3233 ControlFlag = CfCheckSelection;\r
48a9d5f7 3234 FindNextMenu (Selection, &Repaint, &NewLine);\r
b18e7050 3235 break;\r
7936fb6a 3236\r
3237 case CfUiLeft:\r
3238 ControlFlag = CfCheckSelection;\r
c9325700 3239 ASSERT(MenuOption != NULL);\r
7936fb6a 3240 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3241 if (MenuOption->Sequence != 0) {\r
3242 //\r
3243 // In the middle or tail of the Date/Time op-code set, go left.\r
3244 //\r
c9325700 3245 ASSERT(NewPos != NULL);\r
7936fb6a 3246 NewPos = NewPos->BackLink;\r
3247 }\r
3248 }\r
3249 break;\r
3250\r
3251 case CfUiRight:\r
3252 ControlFlag = CfCheckSelection;\r
c9325700 3253 ASSERT(MenuOption != NULL);\r
7936fb6a 3254 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3255 if (MenuOption->Sequence != 2) {\r
3256 //\r
3257 // In the middle or tail of the Date/Time op-code set, go left.\r
3258 //\r
c9325700 3259 ASSERT(NewPos != NULL);\r
7936fb6a 3260 NewPos = NewPos->ForwardLink;\r
3261 }\r
3262 }\r
3263 break;\r
3264\r
3265 case CfUiUp:\r
3266 ControlFlag = CfCheckSelection;\r
3267\r
11232773 3268 SavedListEntry = NewPos;\r
7936fb6a 3269\r
c9325700 3270 ASSERT(NewPos != NULL);\r
11232773
LG
3271 //\r
3272 // Adjust Date/Time position before we advance forward.\r
3273 //\r
3274 AdjustDateAndTimePosition (TRUE, &NewPos);\r
ce6d12cc 3275 if (NewPos->BackLink != &gMenuOption) {\r
11232773 3276 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
715cf6dd 3277 ASSERT (MenuOption != NULL);\r
11232773
LG
3278 NewLine = TRUE;\r
3279 NewPos = NewPos->BackLink;\r
7936fb6a 3280\r
3281 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
5f4ef94a
ED
3282 if (PreviousMenuOption->Row == 0) {\r
3283 UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
3284 }\r
7936fb6a 3285 DistanceValue = PreviousMenuOption->Skip;\r
11232773
LG
3286 Difference = 0;\r
3287 if (MenuOption->Row >= DistanceValue + TopRow) {\r
5f4ef94a 3288 Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
11232773
LG
3289 }\r
3290 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3291 \r
7936fb6a 3292 if (Difference < 0) {\r
3293 //\r
11232773
LG
3294 // We hit the begining MenuOption that can be focused\r
3295 // so we simply scroll to the top.\r
7936fb6a 3296 //\r
11232773 3297 if (TopOfScreen != gMenuOption.ForwardLink) {\r
ce6d12cc 3298 TopOfScreen = gMenuOption.ForwardLink;\r
7936fb6a 3299 Repaint = TRUE;\r
11232773
LG
3300 } else {\r
3301 //\r
3302 // Scroll up to the last page when we have arrived at top page.\r
3303 //\r
3304 NewPos = &gMenuOption;\r
3305 TopOfScreen = &gMenuOption;\r
3306 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3307 ScreenOperation = UiPageUp;\r
3308 ControlFlag = CfScreenOperation;\r
3309 break;\r
7936fb6a 3310 }\r
11232773 3311 } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
1a788cdd
LG
3312 //\r
3313 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
3314 //\r
3315 TopOfScreen = NewPos;\r
3316 Repaint = TRUE;\r
3317 SkipValue = 0;\r
3318 OldSkipValue = 0;\r
11232773
LG
3319 } else if (!IsSelectable (NextMenuOption)) {\r
3320 //\r
3321 // Continue to go up until scroll to next page or the selectable option is found.\r
3322 //\r
3323 ScreenOperation = UiUp;\r
3324 ControlFlag = CfScreenOperation;\r
7936fb6a 3325 }\r
3326\r
3327 //\r
3328 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3329 //\r
3330 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
11232773
LG
3331 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3332 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
b18e7050 3333 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
7936fb6a 3334 } else {\r
11232773
LG
3335 //\r
3336 // Scroll up to the last page.\r
3337 //\r
3338 NewPos = &gMenuOption;\r
3339 TopOfScreen = &gMenuOption;\r
3340 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3341 ScreenOperation = UiPageUp;\r
3342 ControlFlag = CfScreenOperation;\r
7936fb6a 3343 }\r
3344 break;\r
3345\r
3346 case CfUiPageUp:\r
3347 ControlFlag = CfCheckSelection;\r
3348\r
c9325700 3349 ASSERT(NewPos != NULL);\r
ce6d12cc 3350 if (NewPos->BackLink == &gMenuOption) {\r
7936fb6a 3351 NewLine = FALSE;\r
3352 Repaint = FALSE;\r
3353 break;\r
3354 }\r
3355\r
3356 NewLine = TRUE;\r
3357 Repaint = TRUE;\r
3358 Link = TopOfScreen;\r
11232773 3359 Index = BottomRow;\r
ce6d12cc 3360 while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
7936fb6a 3361 Link = Link->BackLink;\r
3362 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
5f4ef94a
ED
3363 if (PreviousMenuOption->Row == 0) {\r
3364 UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
3365 } \r
11232773
LG
3366 if (Index < PreviousMenuOption->Skip) {\r
3367 Index = 0;\r
3368 break;\r
3369 }\r
3370 Index = Index - PreviousMenuOption->Skip;\r
7936fb6a 3371 }\r
11232773
LG
3372 \r
3373 if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
3374 if (TopOfScreen == &gMenuOption) {\r
3375 TopOfScreen = gMenuOption.ForwardLink;\r
3376 NewPos = gMenuOption.BackLink;\r
5f4ef94a 3377 MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3378 Repaint = FALSE;\r
3379 } else if (TopOfScreen != Link) {\r
3380 TopOfScreen = Link;\r
3381 NewPos = Link;\r
5f4ef94a 3382 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3383 } else {\r
3384 //\r
3385 // Finally we know that NewPos is the last MenuOption can be focused.\r
3386 //\r
3387 Repaint = FALSE;\r
3388 NewPos = Link;\r
5f4ef94a 3389 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3390 }\r
3391 } else {\r
3392 if (Index + 1 < TopRow) {\r
3393 //\r
3394 // Back up the previous option.\r
3395 //\r
3396 Link = Link->ForwardLink;\r
3397 }\r
7936fb6a 3398\r
7936fb6a 3399 //\r
11232773 3400 // Move to the option in Next page.\r
7936fb6a 3401 //\r
11232773
LG
3402 if (TopOfScreen == &gMenuOption) {\r
3403 NewPos = gMenuOption.BackLink;\r
5f4ef94a 3404 MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3405 } else {\r
3406 NewPos = Link;\r
5f4ef94a 3407 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3408 }\r
3409\r
7936fb6a 3410 //\r
11232773 3411 // There are more MenuOption needing scrolling up.\r
7936fb6a 3412 //\r
11232773
LG
3413 TopOfScreen = Link;\r
3414 MenuOption = NULL;\r
7936fb6a 3415 }\r
3416\r
3417 //\r
3418 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3419 // Don't do this when we are already in the first page.\r
3420 //\r
3421 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3422 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3423 break;\r
3424\r
3425 case CfUiPageDown:\r
3426 ControlFlag = CfCheckSelection;\r
3427\r
cd7bfc2c 3428 ASSERT (NewPos != NULL);\r
ce6d12cc 3429 if (NewPos->ForwardLink == &gMenuOption) {\r
7936fb6a 3430 NewLine = FALSE;\r
3431 Repaint = FALSE;\r
3432 break;\r
3433 }\r
3434\r
3435 NewLine = TRUE;\r
3436 Repaint = TRUE;\r
3437 Link = TopOfScreen;\r
3438 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3439 Index = TopRow;\r
ce6d12cc 3440 while ((Index <= BottomRow) && (Link->ForwardLink != &gMenuOption)) {\r
7936fb6a 3441 Index = Index + NextMenuOption->Skip;\r
3442 Link = Link->ForwardLink;\r
3443 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3444 }\r
3445\r
11232773
LG
3446 if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
3447 //\r
3448 // Finally we know that NewPos is the last MenuOption can be focused.\r
3449 //\r
3450 Repaint = FALSE;\r
5f4ef94a 3451 MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
11232773
LG
3452 } else {\r
3453 if (Index - 1 > BottomRow) {\r
3454 //\r
3455 // Back up the previous option.\r
3456 //\r
3457 Link = Link->BackLink;\r
3458 }\r
7936fb6a 3459 //\r
11232773 3460 // There are more MenuOption needing scrolling down.\r
7936fb6a 3461 //\r
3462 TopOfScreen = Link;\r
3463 MenuOption = NULL;\r
7936fb6a 3464 //\r
11232773 3465 // Move to the option in Next page.\r
7936fb6a 3466 //\r
5f4ef94a 3467 MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
7936fb6a 3468 }\r
3469\r
3470 //\r
3471 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3472 // Don't do this when we are already in the last page.\r
3473 //\r
11232773 3474 NewPos = Link;\r
7936fb6a 3475 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3476 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3477 break;\r
3478\r
3479 case CfUiDown:\r
3480 ControlFlag = CfCheckSelection;\r
3481 //\r
3482 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3483 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3484 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
3485 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
3486 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
3487 // the Date/Time op-code.\r
3488 //\r
3489 SavedListEntry = NewPos;\r
11232773 3490 AdjustDateAndTimePosition (FALSE, &NewPos);\r
7936fb6a 3491\r
ce6d12cc 3492 if (NewPos->ForwardLink != &gMenuOption) {\r
7936fb6a 3493 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3494 NewLine = TRUE;\r
3495 NewPos = NewPos->ForwardLink;\r
7936fb6a 3496\r
11232773
LG
3497 Difference = 0;\r
3498 if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
5f4ef94a 3499 Difference = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
11232773
LG
3500 //\r
3501 // We hit the end of MenuOption that can be focused\r
3502 // so we simply scroll to the first page.\r
3503 //\r
3504 if (Difference < 0) {\r
3505 //\r
3506 // Scroll to the first page.\r
3507 //\r
3508 if (TopOfScreen != gMenuOption.ForwardLink) {\r
3509 TopOfScreen = gMenuOption.ForwardLink;\r
3510 Repaint = TRUE;\r
3511 MenuOption = NULL;\r
3512 } else {\r
3513 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3514 }\r
3515 NewPos = gMenuOption.ForwardLink;\r
5f4ef94a 3516 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3517 \r
3518 //\r
3519 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3520 //\r
3521 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3522 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3523 break;\r
3524 }\r
3525 }\r
1a788cdd
LG
3526 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3527\r
7936fb6a 3528 //\r
3529 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
3530 //\r
5f4ef94a 3531 UpdateOptionSkipLines (Selection, NextMenuOption);\r
11232773 3532 DistanceValue = Difference + NextMenuOption->Skip;\r
7936fb6a 3533\r
3534 Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
3535 if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
3536 (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
3537 NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
3538 ) {\r
3539 Temp ++;\r
3540 }\r
3541\r
3542 //\r
3543 // If we are going to scroll, update TopOfScreen\r
3544 //\r
3545 if (Temp > BottomRow) {\r
3546 do {\r
3547 //\r
3548 // Is the current top of screen a zero-advance op-code?\r
3549 // If so, keep moving forward till we hit a >0 advance op-code\r
3550 //\r
3551 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
3552\r
3553 //\r
3554 // If bottom op-code is more than one line or top op-code is more than one line\r
3555 //\r
3556 if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {\r
3557 //\r
3558 // Is the bottom op-code greater than or equal in size to the top op-code?\r
3559 //\r
3560 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
3561 //\r
3562 // Skip the top op-code\r
3563 //\r
3564 TopOfScreen = TopOfScreen->ForwardLink;\r
3565 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
3566\r
3567 OldSkipValue = Difference;\r
3568\r
3569 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
3570\r
3571 //\r
3572 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
3573 //\r
1a788cdd 3574 while (Difference >= (INTN) SavedMenuOption->Skip) {\r
7936fb6a 3575 //\r
3576 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
3577 //\r
1a788cdd 3578 Difference = Difference - (INTN) SavedMenuOption->Skip;\r
7936fb6a 3579 TopOfScreen = TopOfScreen->ForwardLink;\r
3580 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
7936fb6a 3581 }\r
3582 //\r
3583 // Since we will act on this op-code in the next routine, and increment the\r
3584 // SkipValue, set the skips to one less than what is required.\r
3585 //\r
3586 SkipValue = Difference - 1;\r
3587\r
3588 } else {\r
3589 //\r
3590 // Since we will act on this op-code in the next routine, and increment the\r
3591 // SkipValue, set the skips to one less than what is required.\r
3592 //\r
3593 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
3594 }\r
3595 } else {\r
3596 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
3597 TopOfScreen = TopOfScreen->ForwardLink;\r
3598 break;\r
3599 } else {\r
3600 SkipValue = OldSkipValue;\r
3601 }\r
3602 }\r
3603 //\r
3604 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
3605 // Let's set a skip flag to smoothly scroll the top of the screen.\r
3606 //\r
3607 if (SavedMenuOption->Skip > 1) {\r
3608 if (SavedMenuOption == NextMenuOption) {\r
3609 SkipValue = 0;\r
3610 } else {\r
3611 SkipValue++;\r
3612 }\r
1a788cdd
LG
3613 } else if (SavedMenuOption->Skip == 1) {\r
3614 SkipValue = 0;\r
7936fb6a 3615 } else {\r
3616 SkipValue = 0;\r
3617 TopOfScreen = TopOfScreen->ForwardLink;\r
3618 }\r
3619 } while (SavedMenuOption->Skip == 0);\r
3620\r
3621 Repaint = TRUE;\r
3622 OldSkipValue = SkipValue;\r
11232773
LG
3623 } else if (!IsSelectable (NextMenuOption)) {\r
3624 //\r
3625 // Continue to go down until scroll to next page or the selectable option is found.\r
3626 //\r
3627 ScreenOperation = UiDown;\r
3628 ControlFlag = CfScreenOperation;\r
7936fb6a 3629 }\r
3630\r
3631 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3632\r
b18e7050 3633 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
7936fb6a 3634\r
3635 } else {\r
7936fb6a 3636 //\r
11232773 3637 // Scroll to the first page.\r
7936fb6a 3638 //\r
11232773
LG
3639 if (TopOfScreen != gMenuOption.ForwardLink) {\r
3640 TopOfScreen = gMenuOption.ForwardLink;\r
3641 Repaint = TRUE;\r
3642 MenuOption = NULL;\r
3643 } else {\r
3644 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3645 }\r
3646 NewLine = TRUE;\r
3647 NewPos = gMenuOption.ForwardLink;\r
5f4ef94a 3648 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
7936fb6a 3649 }\r
11232773
LG
3650\r
3651 //\r
3652 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3653 //\r
3654 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3655 AdjustDateAndTimePosition (TRUE, &NewPos);\r
7936fb6a 3656 break;\r
3657\r
48a9d5f7 3658 case CfUiHotKey:\r
7936fb6a 3659 ControlFlag = CfCheckSelection;\r
48a9d5f7
LG
3660 \r
3661 Status = EFI_SUCCESS;\r
7936fb6a 3662 //\r
48a9d5f7 3663 // Discard changes. After it, no NV flag is showed.\r
7936fb6a 3664 //\r
48a9d5f7
LG
3665 if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
3666 Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3667 if (!EFI_ERROR (Status)) {\r
3668 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3669 Selection->Statement = NULL;\r
3670 gResetRequired = FALSE;\r
3671 } else {\r
3672 do {\r
3673 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString);\r
3674 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3675 //\r
3676 // Still show current page.\r
3677 //\r
3678 Selection->Action = UI_ACTION_NONE;\r
3679 Repaint = TRUE;\r
3680 NewLine = TRUE;\r
3681 break;\r
3682 }\r
3683 }\r
7936fb6a 3684\r
48a9d5f7
LG
3685 //\r
3686 // Reterieve default setting. After it. NV flag will be showed.\r
3687 //\r
3688 if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
3689 Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope);\r
3690 if (!EFI_ERROR (Status)) {\r
3691 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3692 Selection->Statement = NULL;\r
3693 gResetRequired = TRUE;\r
3694 } else {\r
3695 do {\r
3696 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString);\r
3697 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3698 //\r
3699 // Still show current page.\r
3700 //\r
3701 Selection->Action = UI_ACTION_NONE;\r
3702 Repaint = TRUE;\r
3703 NewLine = TRUE;\r
3704 break;\r
3705 }\r
3706 }\r
7936fb6a 3707\r
48a9d5f7
LG
3708 //\r
3709 // Save changes. After it, no NV flag is showed.\r
3710 //\r
3711 if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
3712 Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3713 if (!EFI_ERROR (Status)) {\r
3714 ASSERT(MenuOption != NULL);\r
3715 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3716 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3717 } else {\r
3718 do {\r
3719 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString);\r
3720 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3721 //\r
3722 // Still show current page.\r
3723 //\r
3724 Selection->Action = UI_ACTION_NONE;\r
3725 Repaint = TRUE;\r
3726 NewLine = TRUE;\r
3727 break;\r
3728 }\r
3729 }\r
3730 \r
3731 //\r
3732 // Set Reset required Flag\r
3733 //\r
3734 if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
3735 gResetRequired = TRUE;\r
3736 }\r
3737 \r
3738 //\r
3739 // Exit Action\r
3740 //\r
3741 if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
3742 //\r
3743 // Form Exit without saving, Similar to ESC Key.\r
3744 // FormSet Exit without saving, Exit SendForm.\r
3745 // System Exit without saving, CallExitHandler and Exit SendForm.\r
3746 //\r
3747 DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3748 if (gBrowserSettingScope == FormLevel) {\r
3749 ControlFlag = CfUiReset;\r
3750 } else if (gBrowserSettingScope == FormSetLevel) {\r
3751 Selection->Action = UI_ACTION_EXIT;\r
3752 } else if (gBrowserSettingScope == SystemLevel) {\r
3753 if (ExitHandlerFunction != NULL) {\r
3754 ExitHandlerFunction ();\r
3755 }\r
3756 Selection->Action = UI_ACTION_EXIT;\r
3757 }\r
3758 Selection->Statement = NULL;\r
7936fb6a 3759 }\r
3760 break;\r
3761\r
3762 case CfUiDefault:\r
3763 ControlFlag = CfCheckSelection;\r
4f33c838 3764 //\r
48a9d5f7 3765 // Reset to default value for all forms in the whole system.\r
4f33c838 3766 //\r
48a9d5f7 3767 Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel);\r
7936fb6a 3768\r
3769 if (!EFI_ERROR (Status)) {\r
3770 Selection->Action = UI_ACTION_REFRESH_FORM;\r
ebe43565 3771 Selection->Statement = NULL;\r
15713670 3772 gResetRequired = TRUE;\r
7936fb6a 3773 }\r
3774 break;\r
3775\r
3776 case CfUiNoOperation:\r
3777 ControlFlag = CfCheckSelection;\r
3778 break;\r
3779\r
3780 case CfExit:\r
3781 UiFreeRefreshList ();\r
3782\r
3783 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
3784 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3785 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3786 gST->ConOut->OutputString (gST->ConOut, L"\n");\r
3787\r
3788 return EFI_SUCCESS;\r
3789\r
3790 default:\r
3791 break;\r
3792 }\r
3793 }\r
3794}\r