]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Refine the code to have same function to process the string info. Also update the...
[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
5ea466a5 1311 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
7936fb6a 1312\r
1313 @param InputString String description for this option.\r
1314 @param LineWidth Width of the desired string to extract in CHAR16\r
1315 characters\r
1316 @param Index Where in InputString to start the copy process\r
1317 @param OutputString Buffer to copy the string into\r
1318\r
1319 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
1320\r
1321**/\r
1322UINT16\r
1323GetLineByWidth (\r
1324 IN CHAR16 *InputString,\r
1325 IN UINT16 LineWidth,\r
1326 IN OUT UINTN *Index,\r
1327 OUT CHAR16 **OutputString\r
1328 )\r
1329{\r
1330 UINT16 Count;\r
1331 UINT16 Count2;\r
1332\r
1333 if (GetLineByWidthFinished) {\r
1334 GetLineByWidthFinished = FALSE;\r
1335 return (UINT16) 0;\r
1336 }\r
1337\r
1338 Count = LineWidth;\r
1339 Count2 = 0;\r
1340\r
1341 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
1342\r
1343 //\r
1344 // Ensure we have got a valid buffer\r
1345 //\r
1346 if (*OutputString != NULL) {\r
1347\r
1348 //\r
1349 //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
1350 //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
1351 //\r
1352 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
1353 *Index = *Index + 2;\r
1354 }\r
1355\r
1356 //\r
5ea466a5 1357 // Fast-forward the string and see if there is a carriage-return or linefeed in the string\r
7936fb6a 1358 //\r
5ea466a5 1359 for (; (InputString[*Index + Count2] != CHAR_LINEFEED) && (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
7936fb6a 1360 ;\r
1361\r
1362 //\r
1363 // Copy the desired LineWidth of data to the output buffer.\r
1364 // Also make sure that we don't copy more than the string.\r
1365 // Also make sure that if there are linefeeds, we account for them.\r
1366 //\r
1367 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
1368 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
1369 ) {\r
1370 //\r
1371 // Convert to CHAR16 value and show that we are done with this operation\r
1372 //\r
1373 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
1374 if (LineWidth != 0) {\r
1375 GetLineByWidthFinished = TRUE;\r
1376 }\r
1377 } else {\r
1378 if (Count2 == LineWidth) {\r
1379 //\r
1380 // Rewind the string from the maximum size until we see a space to break the line\r
1381 //\r
1382 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
1383 ;\r
1384 if (LineWidth == 0) {\r
1385 LineWidth = Count;\r
1386 }\r
1387 } else {\r
1388 LineWidth = Count2;\r
1389 }\r
1390 }\r
1391\r
1392 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
1393\r
1394 //\r
5ea466a5 1395 // If currently pointing to a space or carriage-return or linefeed, increment the index to the first non-space character\r
7936fb6a 1396 //\r
1397 for (;\r
5ea466a5 1398 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN)|| (InputString[*Index + LineWidth] == CHAR_LINEFEED);\r
7936fb6a 1399 (*Index)++\r
1400 )\r
1401 ;\r
1402 *Index = (UINT16) (*Index + LineWidth);\r
1403 return LineWidth;\r
1404 } else {\r
1405 return (UINT16) 0;\r
1406 }\r
1407}\r
1408\r
1409\r
1410/**\r
1411 Update display lines for a Menu Option.\r
1412\r
1413 @param Selection The user's selection.\r
1414 @param MenuOption The MenuOption to be checked.\r
7936fb6a 1415\r
7936fb6a 1416**/\r
1417VOID\r
1418UpdateOptionSkipLines (\r
1419 IN UI_MENU_SELECTION *Selection,\r
5f4ef94a 1420 IN UI_MENU_OPTION *MenuOption\r
7936fb6a 1421 )\r
1422{\r
1423 UINTN Index;\r
1424 UINT16 Width;\r
1425 UINTN Row;\r
1426 UINTN OriginalRow;\r
1427 CHAR16 *OutputString;\r
1428 CHAR16 *OptionString;\r
1429\r
1430 Row = 0;\r
5f4ef94a 1431 OptionString = NULL;\r
7936fb6a 1432 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
1433\r
1434 if (OptionString != NULL) {\r
1435 Width = (UINT16) gOptionBlockWidth;\r
1436\r
1437 OriginalRow = Row;\r
1438\r
1439 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1440 //\r
1441 // If there is more string to process print on the next row and increment the Skip value\r
1442 //\r
d1a54e2c 1443 if (StrLen (&OptionString[Index]) != 0) {\r
5f4ef94a
ED
1444 Row++;\r
1445 //\r
1446 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1447 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1448 // some testing to ensure we are keeping this in-sync.\r
1449 //\r
1450 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1451 //\r
1452 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1453 MenuOption->Skip++;\r
7936fb6a 1454 }\r
1455 }\r
1456\r
f4113e1f 1457 FreePool (OutputString);\r
7936fb6a 1458 }\r
1459\r
1460 Row = OriginalRow;\r
1461 }\r
1462\r
5f4ef94a
ED
1463 if (OptionString != NULL) {\r
1464 FreePool (OptionString);\r
1465 }\r
7936fb6a 1466}\r
1467\r
1468\r
1469/**\r
1470 Check whether this Menu Option could be highlighted.\r
1471\r
1472 This is an internal function.\r
1473\r
1474 @param MenuOption The MenuOption to be checked.\r
1475\r
1476 @retval TRUE This Menu Option is selectable.\r
1477 @retval FALSE This Menu Option could not be selected.\r
1478\r
1479**/\r
1480BOOLEAN\r
1481IsSelectable (\r
1482 UI_MENU_OPTION *MenuOption\r
1483 )\r
1484{\r
1485 if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1486 MenuOption->GrayOut || MenuOption->ReadOnly) {\r
1487 return FALSE;\r
1488 } else {\r
1489 return TRUE;\r
1490 }\r
1491}\r
1492\r
1493\r
1494/**\r
1495 Determine if the menu is the last menu that can be selected.\r
1496\r
1497 This is an internal function.\r
d66e6c16 1498\r
7936fb6a 1499 @param Direction The scroll direction. False is down. True is up.\r
1500 @param CurrentPos The current focus.\r
1501\r
1502 @return FALSE -- the menu isn't the last menu that can be selected.\r
1503 @return TRUE -- the menu is the last menu that can be selected.\r
1504\r
1505**/\r
1506BOOLEAN\r
1507ValueIsScroll (\r
1508 IN BOOLEAN Direction,\r
1509 IN LIST_ENTRY *CurrentPos\r
1510 )\r
1511{\r
1512 LIST_ENTRY *Temp;\r
7936fb6a 1513\r
1514 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
1515\r
ce6d12cc 1516 if (Temp == &gMenuOption) {\r
7936fb6a 1517 return TRUE;\r
1518 }\r
1519\r
11232773 1520 return FALSE;\r
7936fb6a 1521}\r
1522\r
1523\r
1524/**\r
1525 Move to next selectable statement.\r
d66e6c16 1526\r
7936fb6a 1527 This is an internal function.\r
d66e6c16 1528\r
5f4ef94a 1529 @param Selection Menu selection.\r
7936fb6a 1530 @param GoUp The navigation direction. TRUE: up, FALSE: down.\r
1531 @param CurrentPosition Current position.\r
11232773 1532 @param GapToTop Gap position to top or bottom.\r
7936fb6a 1533\r
1534 @return The row distance from current MenuOption to next selectable MenuOption.\r
1535\r
1536**/\r
1537INTN\r
1538MoveToNextStatement (\r
5f4ef94a 1539 IN UI_MENU_SELECTION *Selection,\r
7936fb6a 1540 IN BOOLEAN GoUp,\r
11232773
LG
1541 IN OUT LIST_ENTRY **CurrentPosition,\r
1542 IN UINTN GapToTop\r
7936fb6a 1543 )\r
1544{\r
1545 INTN Distance;\r
1546 LIST_ENTRY *Pos;\r
7936fb6a 1547 UI_MENU_OPTION *NextMenuOption;\r
11232773 1548 UI_MENU_OPTION *PreMenuOption;\r
7936fb6a 1549\r
11232773
LG
1550 Distance = 0;\r
1551 Pos = *CurrentPosition;\r
1552 PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
7936fb6a 1553\r
1554 while (TRUE) {\r
1555 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
5f4ef94a
ED
1556 if (NextMenuOption->Row == 0) {\r
1557 UpdateOptionSkipLines (Selection, NextMenuOption);\r
1558 }\r
1559 \r
11232773
LG
1560 if (GoUp && (PreMenuOption != NextMenuOption)) {\r
1561 //\r
1562 // Current Position doesn't need to be caculated when go up.\r
1563 // Caculate distanct at first when go up\r
1564 //\r
1565 if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
1566 NextMenuOption = PreMenuOption;\r
1567 break;\r
1568 }\r
1569 Distance += NextMenuOption->Skip;\r
1570 }\r
7936fb6a 1571 if (IsSelectable (NextMenuOption)) {\r
1572 break;\r
1573 }\r
ce6d12cc 1574 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
11232773
LG
1575 //\r
1576 // Arrive at top.\r
1577 //\r
1578 Distance = -1;\r
7936fb6a 1579 break;\r
1580 }\r
11232773
LG
1581 if (!GoUp) {\r
1582 //\r
1583 // Caculate distanct at later when go down\r
1584 //\r
1585 if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
1586 NextMenuOption = PreMenuOption;\r
7936fb6a 1587 break;\r
1588 }\r
11232773 1589 Distance += NextMenuOption->Skip;\r
7936fb6a 1590 }\r
11232773
LG
1591 PreMenuOption = NextMenuOption;\r
1592 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
7936fb6a 1593 }\r
1594\r
1595 *CurrentPosition = &NextMenuOption->Link;\r
1596 return Distance;\r
1597}\r
1598\r
1599\r
1600/**\r
1601 Adjust Data and Time position accordingly.\r
1602 Data format : [01/02/2004] [11:22:33]\r
1603 Line number : 0 0 1 0 0 1\r
d66e6c16 1604\r
7936fb6a 1605 This is an internal function.\r
1606\r
1607 @param DirectionUp the up or down direction. False is down. True is\r
1608 up.\r
1609 @param CurrentPosition Current position. On return: Point to the last\r
1610 Option (Year or Second) if up; Point to the first\r
1611 Option (Month or Hour) if down.\r
1612\r
1613 @return Return line number to pad. It is possible that we stand on a zero-advance\r
1614 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
1615\r
1616**/\r
1617UINTN\r
1618AdjustDateAndTimePosition (\r
1619 IN BOOLEAN DirectionUp,\r
1620 IN OUT LIST_ENTRY **CurrentPosition\r
1621 )\r
1622{\r
1623 UINTN Count;\r
1624 LIST_ENTRY *NewPosition;\r
1625 UI_MENU_OPTION *MenuOption;\r
1626 UINTN PadLineNumber;\r
1627\r
1628 PadLineNumber = 0;\r
1629 NewPosition = *CurrentPosition;\r
1630 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1631\r
1632 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
1633 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
1634 //\r
1635 // Calculate the distance from current position to the last Date/Time MenuOption\r
1636 //\r
1637 Count = 0;\r
1638 while (MenuOption->Skip == 0) {\r
1639 Count++;\r
1640 NewPosition = NewPosition->ForwardLink;\r
1641 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);\r
1642 PadLineNumber = 1;\r
1643 }\r
1644\r
1645 NewPosition = *CurrentPosition;\r
1646 if (DirectionUp) {\r
1647 //\r
1648 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
1649 // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
1650 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
1651 // checking can be done.\r
1652 //\r
1653 while (Count++ < 2) {\r
1654 NewPosition = NewPosition->BackLink;\r
1655 }\r
1656 } else {\r
1657 //\r
1658 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
1659 // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
1660 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
1661 // checking can be done.\r
1662 //\r
1663 while (Count-- > 0) {\r
1664 NewPosition = NewPosition->ForwardLink;\r
1665 }\r
1666 }\r
1667\r
1668 *CurrentPosition = NewPosition;\r
1669 }\r
1670\r
1671 return PadLineNumber;\r
1672}\r
1673\r
cb7d01c0 1674/**\r
1675 Find HII Handle in the HII database associated with given Device Path.\r
1676\r
1677 If DevicePath is NULL, then ASSERT.\r
1678\r
1679 @param DevicePath Device Path associated with the HII package list\r
1680 handle.\r
1681\r
1682 @retval Handle HII package list Handle associated with the Device\r
1683 Path.\r
1684 @retval NULL Hii Package list handle is not found.\r
1685\r
1686**/\r
1687EFI_HII_HANDLE\r
1688EFIAPI\r
1689DevicePathToHiiHandle (\r
1690 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1691 )\r
1692{\r
1693 EFI_STATUS Status;\r
1694 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
1695 UINTN BufferSize;\r
1696 UINTN HandleCount;\r
1697 UINTN Index;\r
1698 EFI_HANDLE Handle;\r
1699 EFI_HANDLE DriverHandle;\r
1700 EFI_HII_HANDLE *HiiHandles;\r
1701 EFI_HII_HANDLE HiiHandle;\r
1702\r
1703 ASSERT (DevicePath != NULL);\r
1704\r
1705 TmpDevicePath = DevicePath;\r
1706 //\r
1707 // Locate Device Path Protocol handle buffer\r
1708 //\r
1709 Status = gBS->LocateDevicePath (\r
1710 &gEfiDevicePathProtocolGuid,\r
1711 &TmpDevicePath,\r
1712 &DriverHandle\r
1713 );\r
1714 if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
1715 return NULL;\r
1716 }\r
1717\r
1718 //\r
1719 // Retrieve all HII Handles from HII database\r
1720 //\r
1721 BufferSize = 0x1000;\r
1722 HiiHandles = AllocatePool (BufferSize);\r
1723 ASSERT (HiiHandles != NULL);\r
1724 Status = mHiiDatabase->ListPackageLists (\r
1725 mHiiDatabase,\r
1726 EFI_HII_PACKAGE_TYPE_ALL,\r
1727 NULL,\r
1728 &BufferSize,\r
1729 HiiHandles\r
1730 );\r
1731 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1732 FreePool (HiiHandles);\r
1733 HiiHandles = AllocatePool (BufferSize);\r
1734 ASSERT (HiiHandles != NULL);\r
1735\r
1736 Status = mHiiDatabase->ListPackageLists (\r
1737 mHiiDatabase,\r
1738 EFI_HII_PACKAGE_TYPE_ALL,\r
1739 NULL,\r
1740 &BufferSize,\r
1741 HiiHandles\r
1742 );\r
1743 }\r
1744\r
1745 if (EFI_ERROR (Status)) {\r
1746 FreePool (HiiHandles);\r
1747 return NULL;\r
1748 }\r
1749\r
1750 //\r
1751 // Search Hii Handle by Driver Handle\r
1752 //\r
1753 HiiHandle = NULL;\r
1754 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
1755 for (Index = 0; Index < HandleCount; Index++) {\r
1756 Status = mHiiDatabase->GetPackageListHandle (\r
1757 mHiiDatabase,\r
1758 HiiHandles[Index],\r
1759 &Handle\r
1760 );\r
1761 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
1762 HiiHandle = HiiHandles[Index];\r
1763 break;\r
1764 }\r
1765 }\r
1766\r
1767 FreePool (HiiHandles);\r
1768 return HiiHandle;\r
1769}\r
7936fb6a 1770\r
b2e444aa
ED
1771/**\r
1772 Find HII Handle in the HII database associated with given form set guid.\r
1773\r
1774 If FormSetGuid is NULL, then ASSERT.\r
1775\r
1776 @param ComparingGuid FormSet Guid associated with the HII package list\r
1777 handle.\r
1778\r
1779 @retval Handle HII package list Handle associated with the Device\r
1780 Path.\r
1781 @retval NULL Hii Package list handle is not found.\r
1782\r
1783**/\r
1784EFI_HII_HANDLE\r
1785FormSetGuidToHiiHandle (\r
1786 EFI_GUID *ComparingGuid\r
1787 )\r
1788{\r
1789 EFI_HII_HANDLE *HiiHandles;\r
1790 UINTN Index;\r
1791 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
1792 UINTN BufferSize;\r
1793 UINT32 Offset;\r
1794 UINT32 Offset2;\r
1795 UINT32 PackageListLength;\r
1796 EFI_HII_PACKAGE_HEADER PackageHeader;\r
1797 UINT8 *Package;\r
1798 UINT8 *OpCodeData;\r
1799 EFI_STATUS Status;\r
1800 EFI_HII_HANDLE HiiHandle;\r
1801\r
1802 ASSERT (ComparingGuid != NULL);\r
1803\r
1804 HiiHandle = NULL;\r
1805 //\r
1806 // Get all the Hii handles\r
1807 //\r
1808 HiiHandles = HiiGetHiiHandles (NULL);\r
1809 ASSERT (HiiHandles != NULL);\r
1810\r
1811 //\r
1812 // Search for formset of each class type\r
1813 //\r
1814 for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
1815 BufferSize = 0;\r
1816 HiiPackageList = NULL;\r
1817 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
1818 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1819 HiiPackageList = AllocatePool (BufferSize);\r
1820 ASSERT (HiiPackageList != NULL);\r
1821\r
1822 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
1823 }\r
1824 if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
1825 return NULL;\r
1826 }\r
1827\r
1828 //\r
1829 // Get Form package from this HII package List\r
1830 //\r
1831 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
1832 Offset2 = 0;\r
1833 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
1834\r
1835 while (Offset < PackageListLength) {\r
1836 Package = ((UINT8 *) HiiPackageList) + Offset;\r
1837 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
1838\r
1839 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
1840 //\r
1841 // Search FormSet in this Form Package\r
1842 //\r
1843 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
1844 while (Offset2 < PackageHeader.Length) {\r
1845 OpCodeData = Package + Offset2;\r
1846\r
1847 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
1848 //\r
1849 // Try to compare against formset GUID\r
1850 //\r
1851 if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
1852 HiiHandle = HiiHandles[Index];\r
1853 break;\r
1854 }\r
1855 }\r
1856\r
1857 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
1858 }\r
1859 }\r
1860 if (HiiHandle != NULL) {\r
1861 break;\r
1862 }\r
1863 Offset += PackageHeader.Length;\r
1864 }\r
1865 \r
1866 FreePool (HiiPackageList);\r
1867 if (HiiHandle != NULL) {\r
1868 break;\r
1869 }\r
1870 }\r
1871\r
1872 FreePool (HiiHandles);\r
1873\r
1874 return HiiHandle;\r
1875}\r
1876\r
8ca6180f
ED
1877/**\r
1878 Process the goto op code, update the info in the selection structure.\r
1879\r
1880 @param Statement The statement belong to goto op code.\r
1881 @param Selection The selection info.\r
1882 @param Repaint Whether need to repaint the menu.\r
1883 @param NewLine Whether need to create new line.\r
1884\r
1885 @retval EFI_SUCCESS The menu process successfully.\r
1886 @return Other value if the process failed.\r
1887**/\r
1888EFI_STATUS\r
1889ProcessGotoOpCode (\r
1890 IN OUT FORM_BROWSER_STATEMENT *Statement,\r
1891 IN OUT UI_MENU_SELECTION *Selection,\r
1892 OUT BOOLEAN *Repaint,\r
1893 OUT BOOLEAN *NewLine\r
1894 )\r
1895{\r
1896 CHAR16 *StringPtr;\r
e7fd76d1 1897 UINTN StringLen;\r
8ca6180f
ED
1898 UINTN BufferSize;\r
1899 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1900 CHAR16 TemStr[2];\r
1901 UINT8 *DevicePathBuffer;\r
1902 UINTN Index;\r
1903 UINT8 DigitUint8;\r
1904 FORM_BROWSER_FORM *RefForm;\r
1905 EFI_INPUT_KEY Key;\r
1906 EFI_STATUS Status;\r
1907 UI_MENU_LIST *MenuList;\r
b2e444aa 1908 BOOLEAN UpdateFormInfo;\r
8ca6180f
ED
1909 \r
1910 Status = EFI_SUCCESS;\r
b2e444aa 1911 UpdateFormInfo = TRUE;\r
e7fd76d1
ED
1912 StringPtr = NULL;\r
1913 StringLen = 0;\r
8ca6180f 1914\r
e7fd76d1
ED
1915 //\r
1916 // Prepare the device path check, get the device path info first.\r
1917 //\r
8ca6180f 1918 if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
e7fd76d1
ED
1919 StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
1920 if (StringPtr != NULL) {\r
1921 StringLen = StrLen (StringPtr);\r
1922 }\r
1923 }\r
1924\r
1925 //\r
1926 // Check whether the device path string is a valid string.\r
1927 //\r
1928 if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringLen != 0) {\r
8ca6180f
ED
1929 if (Selection->Form->ModalForm) {\r
1930 return Status;\r
1931 }\r
1932 //\r
1933 // Goto another Hii Package list\r
1934 //\r
1935 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
8ca6180f
ED
1936 BufferSize = StrLen (StringPtr) / 2;\r
1937 DevicePath = AllocatePool (BufferSize);\r
1938 ASSERT (DevicePath != NULL);\r
1939\r
1940 //\r
1941 // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
1942 //\r
1943 DevicePathBuffer = (UINT8 *) DevicePath;\r
1944 for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
1945 TemStr[0] = StringPtr[Index];\r
1946 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
1947 if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
1948 //\r
1949 // Invalid Hex Char as the tail.\r
1950 //\r
1951 break;\r
1952 }\r
1953 if ((Index & 1) == 0) {\r
1954 DevicePathBuffer [Index/2] = DigitUint8;\r
1955 } else {\r
1956 DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
1957 }\r
1958 }\r
e7fd76d1 1959 FreePool (StringPtr);\r
8ca6180f
ED
1960\r
1961 Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
e7fd76d1
ED
1962 FreePool (DevicePath);\r
1963\r
8ca6180f
ED
1964 if (Selection->Handle == NULL) {\r
1965 //\r
1966 // If target Hii Handle not found, exit\r
1967 //\r
1968 Selection->Action = UI_ACTION_EXIT;\r
1969 Selection->Statement = NULL;\r
1970 return Status;\r
1971 }\r
1972\r
8ca6180f
ED
1973 CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
1974 Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
1975 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
1976 } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
1977 if (Selection->Form->ModalForm) {\r
1978 return Status;\r
1979 } \r
1980 //\r
1981 // Goto another Formset, check for uncommitted data\r
1982 //\r
1983 Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
b2e444aa
ED
1984 \r
1985 Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
1986 if (Selection->Handle == NULL) {\r
1987 //\r
1988 // If target Hii Handle not found, exit\r
1989 //\r
1990 Selection->Action = UI_ACTION_EXIT;\r
1991 Selection->Statement = NULL;\r
1992 return Status;\r
1993 } \r
8ca6180f
ED
1994\r
1995 CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
1996 Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
1997 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
1998 } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
1999 //\r
2000 // Check whether target From is suppressed.\r
2001 //\r
2002 RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
2003\r
2004 if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
31585af4 2005 if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
8ca6180f
ED
2006 //\r
2007 // Form is suppressed. \r
2008 //\r
2009 do {\r
2010 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
2011 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
2012 if (Repaint != NULL) {\r
2013 *Repaint = TRUE;\r
2014 }\r
2015 return Status;\r
2016 }\r
2017 }\r
2018\r
2019 //\r
2020 // Goto another form inside this formset,\r
2021 //\r
2022 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2023\r
8ca6180f
ED
2024 Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
2025 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
2026 } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
2027 //\r
2028 // Goto another Question\r
2029 //\r
2030 Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
2031\r
2032 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
2033 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2034 } else {\r
2035 if (Repaint != NULL) {\r
2036 *Repaint = TRUE;\r
2037 }\r
2038 if (NewLine != NULL) {\r
2039 *NewLine = TRUE;\r
2040 }\r
2041 }\r
b2e444aa 2042 UpdateFormInfo = FALSE;\r
8ca6180f
ED
2043 } else {\r
2044 if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
2045 Selection->Action = UI_ACTION_REFRESH_FORM;\r
2046 }\r
b2e444aa
ED
2047 UpdateFormInfo = FALSE;\r
2048 }\r
2049\r
2050 if (UpdateFormInfo) {\r
2051 //\r
2052 // Link current form so that we can always go back when someone hits the ESC\r
2053 //\r
2054 MenuList = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
2055 if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
2056 MenuList = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
2057 }\r
8ca6180f
ED
2058 }\r
2059\r
2060 return Status;\r
2061}\r
2062\r
7936fb6a 2063/**\r
2064 Display menu and wait for user to select one menu option, then return it.\r
2065 If AutoBoot is enabled, then if user doesn't select any option,\r
2066 after period of time, it will automatically return the first menu option.\r
2067\r
2068 @param Selection Menu selection.\r
2069\r
2070 @retval EFI_SUCESSS This function always return successfully for now.\r
2071\r
2072**/\r
2073EFI_STATUS\r
2074UiDisplayMenu (\r
2075 IN OUT UI_MENU_SELECTION *Selection\r
2076 )\r
2077{\r
2078 INTN SkipValue;\r
2079 INTN Difference;\r
2080 INTN OldSkipValue;\r
2081 UINTN DistanceValue;\r
2082 UINTN Row;\r
2083 UINTN Col;\r
2084 UINTN Temp;\r
2085 UINTN Temp2;\r
2086 UINTN TopRow;\r
2087 UINTN BottomRow;\r
2088 UINTN OriginalRow;\r
2089 UINTN Index;\r
7936fb6a 2090 UINT16 Width;\r
2091 CHAR16 *StringPtr;\r
2092 CHAR16 *OptionString;\r
2093 CHAR16 *OutputString;\r
ba46ab94
ED
2094 CHAR16 *HelpString;\r
2095 CHAR16 *HelpHeaderString;\r
2096 CHAR16 *HelpBottomString;\r
7936fb6a 2097 BOOLEAN NewLine;\r
2098 BOOLEAN Repaint;\r
2099 BOOLEAN SavedValue;\r
ce6d12cc 2100 BOOLEAN UpArrow;\r
2101 BOOLEAN DownArrow;\r
11232773 2102 BOOLEAN InitializedFlag;\r
7936fb6a 2103 EFI_STATUS Status;\r
2104 EFI_INPUT_KEY Key;\r
2105 LIST_ENTRY *Link;\r
2106 LIST_ENTRY *NewPos;\r
2107 LIST_ENTRY *TopOfScreen;\r
2108 LIST_ENTRY *SavedListEntry;\r
2109 UI_MENU_OPTION *MenuOption;\r
2110 UI_MENU_OPTION *NextMenuOption;\r
2111 UI_MENU_OPTION *SavedMenuOption;\r
2112 UI_MENU_OPTION *PreviousMenuOption;\r
2113 UI_CONTROL_FLAG ControlFlag;\r
2114 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
2115 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
211cc6e5 2116 MENU_REFRESH_ENTRY *MenuUpdateEntry; \r
7936fb6a 2117 UI_SCREEN_OPERATION ScreenOperation;\r
2118 UINT8 MinRefreshInterval;\r
7936fb6a 2119 UINT16 DefaultId;\r
7936fb6a 2120 FORM_BROWSER_STATEMENT *Statement;\r
d66e6c16 2121 UI_MENU_LIST *CurrentMenu;\r
b00964a9 2122 UINTN ModalSkipColumn;\r
48a9d5f7 2123 BROWSER_HOT_KEY *HotKey;\r
ba46ab94
ED
2124 UINTN HelpPageIndex;\r
2125 UINTN HelpPageCount;\r
2126 UINTN RowCount;\r
2127 UINTN HelpLine;\r
2128 UINTN HelpHeaderLine;\r
2129 UINTN HelpBottomLine;\r
2130 BOOLEAN MultiHelpPage;\r
7936fb6a 2131\r
2132 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
2133\r
2134 Status = EFI_SUCCESS;\r
ba46ab94
ED
2135 HelpString = NULL;\r
2136 HelpHeaderString = NULL;\r
2137 HelpBottomString = NULL;\r
7936fb6a 2138 OptionString = NULL;\r
2139 ScreenOperation = UiNoOperation;\r
2140 NewLine = TRUE;\r
2141 MinRefreshInterval = 0;\r
2142 DefaultId = 0;\r
ba46ab94
ED
2143 HelpPageCount = 0;\r
2144 HelpLine = 0;\r
2145 RowCount = 0;\r
2146 HelpBottomLine = 0;\r
2147 HelpHeaderLine = 0;\r
2148 HelpPageIndex = 0;\r
2149 MultiHelpPage = FALSE;\r
7936fb6a 2150\r
2151 OutputString = NULL;\r
ce6d12cc 2152 UpArrow = FALSE;\r
2153 DownArrow = FALSE;\r
7936fb6a 2154 SkipValue = 0;\r
2155 OldSkipValue = 0;\r
2156 MenuRefreshEntry = gMenuRefreshHead;\r
2157\r
2158 NextMenuOption = NULL;\r
2159 PreviousMenuOption = NULL;\r
2160 SavedMenuOption = NULL;\r
48a9d5f7 2161 HotKey = NULL;\r
b00964a9 2162 ModalSkipColumn = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6;\r
7936fb6a 2163\r
2164 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
2165\r
40245175 2166 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE){\r
7936fb6a 2167 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2168 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2169 } else {\r
2170 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2171 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
2172 }\r
2173\r
b00964a9
ED
2174 if (Selection->Form->ModalForm) {\r
2175 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
2176 } else {\r
2177 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
2178 }\r
2179\r
48a9d5f7 2180 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1;\r
7936fb6a 2181\r
2182 Selection->TopRow = TopRow;\r
2183 Selection->BottomRow = BottomRow;\r
2184 Selection->PromptCol = Col;\r
2185 Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
2186 Selection->Statement = NULL;\r
2187\r
ce6d12cc 2188 TopOfScreen = gMenuOption.ForwardLink;\r
7936fb6a 2189 Repaint = TRUE;\r
2190 MenuOption = NULL;\r
2191\r
d66e6c16 2192 //\r
2193 // Find current Menu\r
2194 //\r
2195 CurrentMenu = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
2196 if (CurrentMenu == NULL) {\r
2197 //\r
2198 // Current menu not found, add it to the menu tree\r
2199 //\r
b2e444aa 2200 CurrentMenu = UiAddMenuList (NULL, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
d66e6c16 2201 }\r
2202 ASSERT (CurrentMenu != NULL);\r
b18e7050 2203 Selection->CurrentMenu = CurrentMenu;\r
d66e6c16 2204\r
2205 if (Selection->QuestionId == 0) {\r
2206 //\r
2207 // Highlight not specified, fetch it from cached menu\r
2208 //\r
2209 Selection->QuestionId = CurrentMenu->QuestionId;\r
d88ca2c9 2210 Selection->Sequence = CurrentMenu->Sequence;\r
d66e6c16 2211 }\r
2212\r
7936fb6a 2213 //\r
11232773 2214 // Init option as the current user's selection\r
7936fb6a 2215 //\r
11232773 2216 InitializedFlag = TRUE;\r
ce6d12cc 2217 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 2218\r
2219 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
b18e7050 2220 UpdateStatusBar (Selection, REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
7936fb6a 2221\r
2222 ControlFlag = CfInitialization;\r
2223 Selection->Action = UI_ACTION_NONE;\r
2224 while (TRUE) {\r
2225 switch (ControlFlag) {\r
2226 case CfInitialization:\r
ce6d12cc 2227 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 2228 ControlFlag = CfReadKey;\r
2229 } else {\r
2230 ControlFlag = CfCheckSelection;\r
2231 }\r
2232 break;\r
2233\r
2234 case CfCheckSelection:\r
2235 if (Selection->Action != UI_ACTION_NONE) {\r
2236 ControlFlag = CfExit;\r
2237 } else {\r
2238 ControlFlag = CfRepaint;\r
2239 }\r
2240 break;\r
2241\r
2242 case CfRepaint:\r
2243 ControlFlag = CfRefreshHighLight;\r
2244\r
2245 if (Repaint) {\r
2246 //\r
2247 // Display menu\r
2248 //\r
ce6d12cc 2249 DownArrow = FALSE;\r
2250 UpArrow = FALSE;\r
7936fb6a 2251 Row = TopRow;\r
2252\r
cd7bfc2c
ED
2253 Temp = (UINTN) SkipValue;\r
2254 Temp2 = (UINTN) SkipValue;\r
7936fb6a 2255\r
b00964a9
ED
2256 if (Selection->Form->ModalForm) {\r
2257 ClearLines (\r
2258 LocalScreen.LeftColumn + ModalSkipColumn,\r
2259 LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
2260 TopRow - SCROLL_ARROW_HEIGHT,\r
2261 BottomRow + SCROLL_ARROW_HEIGHT,\r
2262 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2263 ); \r
2264 } else {\r
2265 ClearLines (\r
2266 LocalScreen.LeftColumn,\r
2267 LocalScreen.RightColumn,\r
2268 TopRow - SCROLL_ARROW_HEIGHT,\r
2269 BottomRow + SCROLL_ARROW_HEIGHT,\r
2270 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2271 );\r
2272 }\r
7936fb6a 2273 UiFreeRefreshList ();\r
2274 MinRefreshInterval = 0;\r
2275\r
ce6d12cc 2276 for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
7936fb6a 2277 MenuOption = MENU_OPTION_FROM_LINK (Link);\r
2278 MenuOption->Row = Row;\r
2279 MenuOption->Col = Col;\r
b00964a9
ED
2280 if (Selection->Form->ModalForm) {\r
2281 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn;\r
2282 } else {\r
2283 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
2284 }\r
7936fb6a 2285\r
2286 Statement = MenuOption->ThisTag;\r
2287 if (Statement->InSubtitle) {\r
2288 MenuOption->Col += SUBTITLE_INDENT;\r
2289 }\r
2290\r
2291 if (MenuOption->GrayOut) {\r
2292 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2293 } else {\r
2294 if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
f0a1bf11 2295 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2296 }\r
2297 }\r
2298\r
2299 Width = GetWidth (Statement, MenuOption->Handle);\r
2300 OriginalRow = Row;\r
2301\r
11232773 2302 if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
a605dfb3
LG
2303 //\r
2304 // Print Arrow for Goto button.\r
2305 //\r
2306 PrintAt (\r
b6ca1fd8 2307 MenuOption->Col - 2,\r
a605dfb3
LG
2308 Row,\r
2309 L"%c",\r
2310 GEOMETRICSHAPE_RIGHT_TRIANGLE\r
2311 );\r
2312 }\r
2313\r
7936fb6a 2314 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2315 if ((Temp == 0) && (Row <= BottomRow)) {\r
2316 PrintStringAt (MenuOption->Col, Row, OutputString);\r
2317 }\r
2318 //\r
2319 // If there is more string to process print on the next row and increment the Skip value\r
2320 //\r
d1a54e2c 2321 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2322 if (Temp == 0) {\r
2323 Row++;\r
2324 }\r
2325 }\r
2326\r
f4113e1f 2327 FreePool (OutputString);\r
7936fb6a 2328 if (Temp != 0) {\r
2329 Temp--;\r
2330 }\r
2331 }\r
2332\r
2333 Temp = 0;\r
2334 Row = OriginalRow;\r
2335\r
8d00a0f1 2336 Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2337 if (EFI_ERROR (Status)) {\r
2338 //\r
2339 // Repaint to clear possible error prompt pop-up\r
2340 //\r
2341 Repaint = TRUE;\r
2342 NewLine = TRUE;\r
2343 ControlFlag = CfRepaint;\r
2344 break;\r
2345 }\r
7936fb6a 2346\r
2347 if (OptionString != NULL) {\r
2348 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
4a6876b7 2349 ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
7936fb6a 2350 }\r
2351\r
7936fb6a 2352 Width = (UINT16) gOptionBlockWidth;\r
2353 OriginalRow = Row;\r
2354\r
2355 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2356 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
2357 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
2358 }\r
2359 //\r
2360 // If there is more string to process print on the next row and increment the Skip value\r
2361 //\r
d1a54e2c 2362 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2363 if (Temp2 == 0) {\r
2364 Row++;\r
2365 //\r
2366 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
2367 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
2368 // some testing to ensure we are keeping this in-sync.\r
2369 //\r
2370 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
2371 //\r
2372 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
2373 MenuOption->Skip++;\r
2374 }\r
2375 }\r
2376 }\r
2377\r
f4113e1f 2378 FreePool (OutputString);\r
7936fb6a 2379 if (Temp2 != 0) {\r
2380 Temp2--;\r
2381 }\r
2382 }\r
2383\r
2384 Temp2 = 0;\r
2385 Row = OriginalRow;\r
2386\r
f4113e1f 2387 FreePool (OptionString);\r
7936fb6a 2388 }\r
4ffaadcc
ED
2389\r
2390 //\r
2391 // If Question has refresh guid, register the op-code.\r
2392 //\r
2393 if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
2394 if (gMenuEventGuidRefreshHead == NULL) {\r
2395 MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2396 gMenuEventGuidRefreshHead = MenuUpdateEntry;\r
2397 } else {\r
2398 MenuUpdateEntry = gMenuEventGuidRefreshHead;\r
2399 while (MenuUpdateEntry->Next != NULL) {\r
2400 MenuUpdateEntry = MenuUpdateEntry->Next; \r
2401 }\r
2402 MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2403 MenuUpdateEntry = MenuUpdateEntry->Next; \r
2404 }\r
2405 ASSERT (MenuUpdateEntry != NULL);\r
2406 Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event);\r
2407 ASSERT (!EFI_ERROR (Status));\r
2408 MenuUpdateEntry->MenuOption = MenuOption;\r
2409 MenuUpdateEntry->Selection = Selection;\r
2410 MenuUpdateEntry->CurrentColumn = MenuOption->OptCol;\r
2411 MenuUpdateEntry->CurrentRow = MenuOption->Row;\r
2412 if (MenuOption->GrayOut) {\r
2413 MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2414 } else {\r
2415 MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2416 }\r
2417 }\r
2418 \r
2419 //\r
2420 // If Question request refresh, register the op-code\r
2421 //\r
2422 if (Statement->RefreshInterval != 0) {\r
2423 //\r
2424 // Menu will be refreshed at minimal interval of all Questions\r
2425 // which have refresh request\r
2426 //\r
2427 if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
2428 MinRefreshInterval = Statement->RefreshInterval;\r
2429 }\r
2430 \r
2431 if (gMenuRefreshHead == NULL) {\r
2432 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2433 gMenuRefreshHead = MenuRefreshEntry;\r
2434 } else {\r
2435 MenuRefreshEntry = gMenuRefreshHead;\r
2436 while (MenuRefreshEntry->Next != NULL) {\r
2437 MenuRefreshEntry = MenuRefreshEntry->Next; \r
2438 }\r
2439 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
2440 MenuRefreshEntry = MenuRefreshEntry->Next;\r
2441 }\r
2442 ASSERT (MenuRefreshEntry != NULL); \r
2443 MenuRefreshEntry->MenuOption = MenuOption;\r
2444 MenuRefreshEntry->Selection = Selection;\r
2445 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
2446 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
2447 if (MenuOption->GrayOut) {\r
2448 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2449 } else { \r
2450 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2451 }\r
2452 }\r
2453 \r
7936fb6a 2454 //\r
2455 // If this is a text op with secondary text information\r
2456 //\r
2457 if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
2458 StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle);\r
2459\r
2460 Width = (UINT16) gOptionBlockWidth;\r
2461 OriginalRow = Row;\r
2462\r
2463 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
2464 if ((Temp == 0) && (Row <= BottomRow)) {\r
2465 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
2466 }\r
2467 //\r
2468 // If there is more string to process print on the next row and increment the Skip value\r
2469 //\r
d1a54e2c 2470 if (StrLen (&StringPtr[Index]) != 0) {\r
7936fb6a 2471 if (Temp2 == 0) {\r
2472 Row++;\r
2473 //\r
2474 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
2475 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
2476 // some testing to ensure we are keeping this in-sync.\r
2477 //\r
2478 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
2479 //\r
2480 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
2481 MenuOption->Skip++;\r
2482 }\r
2483 }\r
2484 }\r
2485\r
f4113e1f 2486 FreePool (OutputString);\r
7936fb6a 2487 if (Temp2 != 0) {\r
2488 Temp2--;\r
2489 }\r
2490 }\r
2491\r
2492 Row = OriginalRow;\r
f4113e1f 2493 FreePool (StringPtr);\r
7936fb6a 2494 }\r
f0a1bf11 2495 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2496\r
2497 //\r
2498 // Need to handle the bottom of the display\r
2499 //\r
2500 if (MenuOption->Skip > 1) {\r
2501 Row += MenuOption->Skip - SkipValue;\r
2502 SkipValue = 0;\r
2503 } else {\r
2504 Row += MenuOption->Skip;\r
2505 }\r
2506\r
2507 if (Row > BottomRow) {\r
2508 if (!ValueIsScroll (FALSE, Link)) {\r
ce6d12cc 2509 DownArrow = TRUE;\r
7936fb6a 2510 }\r
2511\r
2512 Row = BottomRow + 1;\r
2513 break;\r
2514 }\r
2515 }\r
2516\r
2517 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
ce6d12cc 2518 UpArrow = TRUE;\r
7936fb6a 2519 }\r
2520\r
ce6d12cc 2521 if (UpArrow) {\r
7936fb6a 2522 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2523 PrintAt (\r
2524 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2525 TopRow - SCROLL_ARROW_HEIGHT,\r
2526 L"%c",\r
2527 ARROW_UP\r
2528 );\r
f0a1bf11 2529 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2530 }\r
2531\r
ce6d12cc 2532 if (DownArrow) {\r
7936fb6a 2533 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
2534 PrintAt (\r
2535 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
2536 BottomRow + SCROLL_ARROW_HEIGHT,\r
2537 L"%c",\r
2538 ARROW_DOWN\r
2539 );\r
f0a1bf11 2540 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2541 }\r
2542\r
2543 MenuOption = NULL;\r
2544 }\r
2545 break;\r
2546\r
2547 case CfRefreshHighLight:\r
2548 //\r
2549 // MenuOption: Last menu option that need to remove hilight\r
2550 // MenuOption is set to NULL in Repaint\r
2551 // NewPos: Current menu option that need to hilight\r
2552 //\r
2553 ControlFlag = CfUpdateHelpString;\r
11232773
LG
2554 if (InitializedFlag) {\r
2555 InitializedFlag = FALSE;\r
5f4ef94a 2556 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773 2557 }\r
7936fb6a 2558\r
2559 //\r
2560 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
2561 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
2562 //\r
2563 SavedValue = Repaint;\r
2564 Repaint = FALSE;\r
2565\r
2566 if (Selection->QuestionId != 0) {\r
ce6d12cc 2567 NewPos = gMenuOption.ForwardLink;\r
7936fb6a 2568 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2569\r
d88ca2c9
ED
2570 while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId ||\r
2571 SavedMenuOption->Sequence != Selection->Sequence) &&\r
2572 NewPos->ForwardLink != &gMenuOption) {\r
7936fb6a 2573 NewPos = NewPos->ForwardLink;\r
2574 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2575 }\r
2576 if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
2577 //\r
2578 // Target Question found, find its MenuOption\r
2579 //\r
2580 Link = TopOfScreen;\r
2581\r
2582 for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
2583 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2584 Index += SavedMenuOption->Skip;\r
5f4ef94a
ED
2585 if (Link == TopOfScreen) {\r
2586 Index -= OldSkipValue;\r
2587 }\r
7936fb6a 2588 Link = Link->ForwardLink;\r
2589 }\r
5f4ef94a
ED
2590 if (NewPos == Link) {\r
2591 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
2592 }\r
7936fb6a 2593\r
08476b33
ED
2594 //\r
2595 // Not find the selected menu in current show page.\r
2596 // Have two case to enter this if:\r
2597 // 1. Not find the menu at current page.\r
2598 // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
2599 // For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
2600 //\r
2601 // Base on the selected menu will show at the bottom of the page,\r
2602 // select the menu which will show at the top of the page.\r
2603 //\r
2604 if (Link != NewPos || Index > BottomRow || \r
2605 (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\r
85aa96cd
ED
2606 //\r
2607 // Find the MenuOption which has the skip value for Date/Time opcode. \r
2608 //\r
2609 AdjustDateAndTimePosition(FALSE, &NewPos);\r
7936fb6a 2610 //\r
2611 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
2612 //\r
5f4ef94a
ED
2613 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
2614 //\r
2615 // SavedMenuOption->Row == 0 means the menu not show yet.\r
2616 //\r
2617 if (SavedMenuOption->Row == 0) {\r
2618 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
2619 }\r
08476b33
ED
2620\r
2621 //\r
2622 // Base on the selected menu will show at the bottome of next page, \r
2623 // select the menu show at the top of the next page. \r
2624 //\r
7936fb6a 2625 Link = NewPos;\r
5f4ef94a 2626 for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) { \r
7936fb6a 2627 Link = Link->BackLink;\r
2628 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
5f4ef94a
ED
2629 if (SavedMenuOption->Row == 0) {\r
2630 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
2631 }\r
08476b33 2632 Index += SavedMenuOption->Skip;\r
7936fb6a 2633 }\r
08476b33
ED
2634\r
2635 //\r
2636 // Found the menu which will show at the top of the page.\r
2637 //\r
2638 if (Link == NewPos) {\r
2639 //\r
2640 // The menu can show more than one pages, just show the menu at the top of the page.\r
2641 //\r
2642 SkipValue = 0;\r
2643 TopOfScreen = Link;\r
2644 OldSkipValue = SkipValue;\r
5f4ef94a 2645 } else {\r
08476b33
ED
2646 //\r
2647 // Check whether need to skip some line for menu shows at the top of the page.\r
2648 //\r
2649 SkipValue = Index - BottomRow - 1;\r
2650 if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
2651 TopOfScreen = Link;\r
2652 OldSkipValue = SkipValue;\r
2653 } else {\r
2654 SkipValue = 0;\r
2655 TopOfScreen = Link->ForwardLink;\r
2656 }\r
5f4ef94a 2657 }\r
7936fb6a 2658\r
2659 Repaint = TRUE;\r
2660 NewLine = TRUE;\r
2661 ControlFlag = CfRepaint;\r
2662 break;\r
2663 }\r
2664 } else {\r
2665 //\r
2666 // Target Question not found, highlight the default menu option\r
2667 //\r
2668 NewPos = TopOfScreen;\r
2669 }\r
2670\r
2671 Selection->QuestionId = 0;\r
2672 }\r
2673\r
2674 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
2675 if (MenuOption != NULL) {\r
2676 //\r
2677 // Remove highlight on last Menu Option\r
2678 //\r
2679 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2680 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
f0a1bf11 2681 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2682 if (OptionString != NULL) {\r
2683 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2684 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
2685 ) {\r
4a6876b7 2686 ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
7936fb6a 2687 }\r
2688\r
2689 Width = (UINT16) gOptionBlockWidth;\r
2690 OriginalRow = MenuOption->Row;\r
2691\r
2692 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2693 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2694 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2695 }\r
2696 //\r
2697 // If there is more string to process print on the next row and increment the Skip value\r
2698 //\r
d1a54e2c 2699 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2700 MenuOption->Row++;\r
2701 }\r
2702\r
f4113e1f 2703 FreePool (OutputString);\r
7936fb6a 2704 }\r
2705\r
2706 MenuOption->Row = OriginalRow;\r
2707\r
f4113e1f 2708 FreePool (OptionString);\r
7936fb6a 2709 } else {\r
2710 if (NewLine) {\r
2711 if (MenuOption->GrayOut) {\r
2712 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
2713 } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
f0a1bf11 2714 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2715 }\r
2716\r
2717 OriginalRow = MenuOption->Row;\r
2718 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
2719\r
2720 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2721 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2722 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2723 }\r
2724 //\r
2725 // If there is more string to process print on the next row and increment the Skip value\r
2726 //\r
d1a54e2c 2727 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2728 MenuOption->Row++;\r
2729 }\r
2730\r
f4113e1f 2731 FreePool (OutputString);\r
7936fb6a 2732 }\r
2733\r
2734 MenuOption->Row = OriginalRow;\r
f0a1bf11 2735 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2736 }\r
2737 }\r
2738 }\r
2739\r
2740 //\r
11232773 2741 // This is the current selected statement\r
7936fb6a 2742 //\r
2743 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
11232773
LG
2744 Statement = MenuOption->ThisTag;\r
2745 Selection->Statement = Statement;\r
7936fb6a 2746 if (!IsSelectable (MenuOption)) {\r
11232773
LG
2747 Repaint = SavedValue;\r
2748 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
7936fb6a 2749 break;\r
2750 }\r
2751\r
d66e6c16 2752 //\r
2753 // Record highlight for current menu\r
2754 //\r
2755 CurrentMenu->QuestionId = Statement->QuestionId;\r
d88ca2c9 2756 CurrentMenu->Sequence = MenuOption->Sequence;\r
7936fb6a 2757\r
2758 //\r
2759 // Set reverse attribute\r
2760 //\r
f0a1bf11 2761 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
7936fb6a 2762 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2763\r
2764 //\r
2765 // Assuming that we have a refresh linked-list created, lets annotate the\r
2766 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
2767 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
2768 //\r
2769 if (gMenuRefreshHead != NULL) {\r
2770 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
81da6ef9 2771 if (MenuRefreshEntry->MenuOption->GrayOut) {\r
1fcd34f8
ED
2772 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
2773 } else { \r
2774 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
2775 }\r
7936fb6a 2776 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
f0a1bf11 2777 MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\r
7936fb6a 2778 }\r
2779 }\r
2780 }\r
2781\r
2782 ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
2783 if (OptionString != NULL) {\r
2784 if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
4a6876b7 2785 ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
7936fb6a 2786 }\r
2787 Width = (UINT16) gOptionBlockWidth;\r
2788\r
2789 OriginalRow = MenuOption->Row;\r
2790\r
2791 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
2792 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2793 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
2794 }\r
2795 //\r
2796 // If there is more string to process print on the next row and increment the Skip value\r
2797 //\r
d1a54e2c 2798 if (StrLen (&OptionString[Index]) != 0) {\r
7936fb6a 2799 MenuOption->Row++;\r
2800 }\r
2801\r
f4113e1f 2802 FreePool (OutputString);\r
7936fb6a 2803 }\r
2804\r
2805 MenuOption->Row = OriginalRow;\r
2806\r
f4113e1f 2807 FreePool (OptionString);\r
7936fb6a 2808 } else {\r
2809 if (NewLine) {\r
2810 OriginalRow = MenuOption->Row;\r
2811\r
2812 Width = GetWidth (Statement, MenuOption->Handle);\r
2813\r
2814 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
2815 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
2816 PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
2817 }\r
2818 //\r
2819 // If there is more string to process print on the next row and increment the Skip value\r
2820 //\r
d1a54e2c 2821 if (StrLen (&MenuOption->Description[Index]) != 0) {\r
7936fb6a 2822 MenuOption->Row++;\r
2823 }\r
2824\r
f4113e1f 2825 FreePool (OutputString);\r
7936fb6a 2826 }\r
2827\r
2828 MenuOption->Row = OriginalRow;\r
2829\r
2830 }\r
2831 }\r
2832\r
8b0fc5c1 2833 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
8d00a0f1 2834\r
7936fb6a 2835 //\r
2836 // Clear reverse attribute\r
2837 //\r
f0a1bf11 2838 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 2839 }\r
2840 //\r
2841 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2842 // if we didn't break halfway when process CfRefreshHighLight.\r
2843 //\r
2844 Repaint = SavedValue;\r
2845 break;\r
2846\r
2847 case CfUpdateHelpString:\r
2848 ControlFlag = CfPrepareToReadKey;\r
b00964a9
ED
2849 if (Selection->Form->ModalForm) {\r
2850 break;\r
2851 }\r
7936fb6a 2852\r
11232773 2853 if (Repaint || NewLine) {\r
7936fb6a 2854 //\r
2855 // Don't print anything if it is a NULL help token\r
2856 //\r
c9325700 2857 ASSERT(MenuOption != NULL);\r
11232773 2858 if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
7936fb6a 2859 StringPtr = L"\0";\r
2860 } else {\r
2861 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2862 }\r
2863\r
ba46ab94
ED
2864 RowCount = BottomRow - TopRow;\r
2865 HelpPageIndex = 0;\r
2866 //\r
2867 // 1.Calculate how many line the help string need to print.\r
2868 //\r
2869 HelpLine = ProcessHelpString (StringPtr, &HelpString, RowCount);\r
2870 if (HelpLine > RowCount) {\r
2871 MultiHelpPage = TRUE;\r
2872 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
2873 HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, RowCount);\r
2874 StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
2875 HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, RowCount);\r
7936fb6a 2876 //\r
ba46ab94 2877 // Calculate the help page count.\r
7936fb6a 2878 //\r
ba46ab94
ED
2879 if (HelpLine > 2 * RowCount - 2) {\r
2880 HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
2881 if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
2882 HelpPageCount += 1;\r
2883 }\r
2884 } else {\r
2885 HelpPageCount = 2;\r
7936fb6a 2886 }\r
ba46ab94
ED
2887 } else {\r
2888 MultiHelpPage = FALSE;\r
2889 }\r
2890 }\r
2891\r
2892 //\r
2893 // Clean the help field first.\r
2894 //\r
2895 ClearLines (\r
2896 LocalScreen.RightColumn - gHelpBlockWidth,\r
2897 LocalScreen.RightColumn,\r
2898 TopRow,\r
2899 BottomRow,\r
2900 PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
2901 );\r
7936fb6a 2902\r
ba46ab94
ED
2903 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
2904 //\r
2905 // Check whether need to show the 'More(U/u)' at the begin.\r
2906 // Base on current direct info, here shows aligned to the right side of the column.\r
2907 // If the direction is multi line and aligned to right side may have problem, so \r
2908 // add ASSERT code here.\r
2909 //\r
2910 if (HelpPageIndex > 0) {\r
2911 for (Index = 0; Index < HelpHeaderLine; Index++) {\r
2912 ASSERT (HelpHeaderLine == 1);\r
2913 ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
2914 PrintStringAt (\r
2915 LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
2916 Index + TopRow,\r
2917 &HelpHeaderString[Index * gHelpBlockWidth * 2]\r
2918 );\r
2919 }\r
2920 }\r
2921\r
2922 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2923 //\r
2924 // Print the help string info.\r
2925 //\r
2926 if (!MultiHelpPage) {\r
5ea466a5 2927 for (Index = 0; Index < HelpLine; Index++) {\r
7936fb6a 2928 PrintStringAt (\r
2929 LocalScreen.RightColumn - gHelpBlockWidth,\r
2930 Index + TopRow,\r
ba46ab94
ED
2931 &HelpString[Index * gHelpBlockWidth * 2]\r
2932 );\r
2933 }\r
2934 } else {\r
2935 if (HelpPageIndex == 0) {\r
2936 for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
2937 PrintStringAt (\r
2938 LocalScreen.RightColumn - gHelpBlockWidth,\r
2939 Index + TopRow,\r
2940 &HelpString[Index * gHelpBlockWidth * 2]\r
2941 );\r
2942 }\r
2943 } else {\r
2944 for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
2945 (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
2946 PrintStringAt (\r
2947 LocalScreen.RightColumn - gHelpBlockWidth,\r
2948 Index + TopRow + HelpHeaderLine,\r
2949 &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* gHelpBlockWidth * 2]\r
2950 );\r
2951 }\r
2952 } \r
2953 }\r
2954\r
2955 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
2956 //\r
2957 // Check whether need to print the 'More(D/d)' at the bottom.\r
2958 // Base on current direct info, here shows aligned to the right side of the column.\r
2959 // If the direction is multi line and aligned to right side may have problem, so \r
2960 // add ASSERT code here.\r
2961 //\r
2962 if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
2963 for (Index = 0; Index < HelpBottomLine; Index++) {\r
2964 ASSERT (HelpBottomLine == 1);\r
2965 ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
2966 PrintStringAt (\r
2967 LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
2968 Index + BottomRow - HelpBottomLine,\r
2969 &HelpBottomString[Index * gHelpBlockWidth * 2]\r
7936fb6a 2970 );\r
2971 }\r
2972 }\r
2973 //\r
2974 // Reset this flag every time we finish using it.\r
2975 //\r
2976 Repaint = FALSE;\r
2977 NewLine = FALSE;\r
2978 break;\r
2979\r
2980 case CfPrepareToReadKey:\r
2981 ControlFlag = CfReadKey;\r
2982 ScreenOperation = UiNoOperation;\r
2983 break;\r
2984\r
2985 case CfReadKey:\r
2986 ControlFlag = CfScreenOperation;\r
2987\r
2988 //\r
2989 // Wait for user's selection\r
2990 //\r
2991 do {\r
2992 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
2993 } while (Status == EFI_TIMEOUT);\r
2994\r
8d00a0f1 2995 if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
7936fb6a 2996 //\r
8d00a0f1 2997 // IFR is updated in Callback of refresh opcode, re-parse it\r
7936fb6a 2998 //\r
48a9d5f7 2999 ControlFlag = CfCheckSelection;\r
8d00a0f1 3000 Selection->Statement = NULL;\r
48a9d5f7 3001 break;\r
8d00a0f1 3002 }\r
3003\r
3004 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3005 //\r
d66e6c16 3006 // If we encounter error, continue to read another key in.\r
8d00a0f1 3007 //\r
3008 if (EFI_ERROR (Status)) {\r
3009 ControlFlag = CfReadKey;\r
3010 break;\r
7936fb6a 3011 }\r
3012\r
7936fb6a 3013 switch (Key.UnicodeChar) {\r
3014 case CHAR_CARRIAGE_RETURN:\r
febca2e3
ED
3015 if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
3016 ControlFlag = CfReadKey;\r
3017 break;\r
3018 }\r
3019\r
7936fb6a 3020 ScreenOperation = UiSelect;\r
3021 gDirection = 0;\r
3022 break;\r
3023\r
3024 //\r
3025 // We will push the adjustment of these numeric values directly to the input handler\r
3026 // NOTE: we won't handle manual input numeric\r
3027 //\r
3028 case '+':\r
3029 case '-':\r
c9325700
ED
3030 //\r
3031 // If the screen has no menu items, and the user didn't select UiReset\r
3032 // ignore the selection and go back to reading keys.\r
3033 //\r
febca2e3 3034 if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
c9325700
ED
3035 ControlFlag = CfReadKey;\r
3036 break;\r
3037 }\r
3038\r
3039 ASSERT(MenuOption != NULL);\r
7936fb6a 3040 Statement = MenuOption->ThisTag;\r
3041 if ((Statement->Operand == EFI_IFR_DATE_OP)\r
3042 || (Statement->Operand == EFI_IFR_TIME_OP)\r
3043 || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
3044 ){\r
3045 if (Key.UnicodeChar == '+') {\r
3046 gDirection = SCAN_RIGHT;\r
3047 } else {\r
3048 gDirection = SCAN_LEFT;\r
3049 }\r
3050 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
8d00a0f1 3051 if (EFI_ERROR (Status)) {\r
3052 //\r
3053 // Repaint to clear possible error prompt pop-up\r
3054 //\r
3055 Repaint = TRUE;\r
3056 NewLine = TRUE;\r
7b546f74
ED
3057 } else {\r
3058 Selection->Action = UI_ACTION_REFRESH_FORM;\r
8d00a0f1 3059 }\r
676df92c 3060 if (OptionString != NULL) {\r
3061 FreePool (OptionString);\r
3062 }\r
7936fb6a 3063 }\r
3064 break;\r
3065\r
3066 case '^':\r
3067 ScreenOperation = UiUp;\r
3068 break;\r
3069\r
3070 case 'V':\r
3071 case 'v':\r
3072 ScreenOperation = UiDown;\r
3073 break;\r
3074\r
3075 case ' ':\r
40245175 3076 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
c9325700
ED
3077 //\r
3078 // If the screen has no menu items, and the user didn't select UiReset\r
3079 // ignore the selection and go back to reading keys.\r
3080 //\r
3081 if(IsListEmpty (&gMenuOption)) {\r
3082 ControlFlag = CfReadKey;\r
3083 break;\r
3084 }\r
3085 \r
3086 ASSERT(MenuOption != NULL);\r
febca2e3 3087 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
7936fb6a 3088 ScreenOperation = UiSelect;\r
3089 }\r
3090 }\r
3091 break;\r
3092\r
ba46ab94
ED
3093 case 'D':\r
3094 case 'd':\r
3095 if (!MultiHelpPage) {\r
3096 ControlFlag = CfReadKey;\r
3097 break;\r
3098 }\r
3099 ControlFlag = CfUpdateHelpString;\r
3100 HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
3101 break;\r
3102\r
3103 case 'U':\r
3104 case 'u':\r
3105 if (!MultiHelpPage) {\r
3106 ControlFlag = CfReadKey;\r
3107 break;\r
3108 }\r
3109 ControlFlag = CfUpdateHelpString;\r
3110 HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
3111 break;\r
3112\r
7936fb6a 3113 case CHAR_NULL:\r
48a9d5f7
LG
3114 for (Index = 0; Index < mScanCodeNumber; Index++) {\r
3115 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
3116 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
3117 break;\r
3118 }\r
3119 }\r
3120 \r
3121 if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
7936fb6a 3122 //\r
48a9d5f7 3123 // ModalForm has no ESC key and Hot Key.\r
7936fb6a 3124 //\r
48a9d5f7
LG
3125 ControlFlag = CfReadKey;\r
3126 } else if (Index == mScanCodeNumber) {\r
3127 //\r
3128 // Check whether Key matches the registered hot key.\r
3129 //\r
3130 HotKey = NULL;\r
3131 if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
3132 HotKey = GetHotKeyFromRegisterList (&Key);\r
3133 }\r
3134 if (HotKey != NULL) {\r
3135 ScreenOperation = UiHotKey;\r
7936fb6a 3136 }\r
3137 }\r
3138 break;\r
3139 }\r
3140 break;\r
3141\r
3142 case CfScreenOperation:\r
d66e6c16 3143 if (ScreenOperation != UiReset) {\r
7936fb6a 3144 //\r
d66e6c16 3145 // If the screen has no menu items, and the user didn't select UiReset\r
7936fb6a 3146 // ignore the selection and go back to reading keys.\r
3147 //\r
ce6d12cc 3148 if (IsListEmpty (&gMenuOption)) {\r
7936fb6a 3149 ControlFlag = CfReadKey;\r
3150 break;\r
3151 }\r
7936fb6a 3152 }\r
3153\r
3154 for (Index = 0;\r
3155 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
3156 Index++\r
3157 ) {\r
3158 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
3159 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
3160 break;\r
3161 }\r
3162 }\r
3163 break;\r
3164\r
7936fb6a 3165 case CfUiSelect:\r
3166 ControlFlag = CfCheckSelection;\r
3167\r
c9325700 3168 ASSERT(MenuOption != NULL);\r
7936fb6a 3169 Statement = MenuOption->ThisTag;\r
e24adb18 3170 if (Statement->Operand == EFI_IFR_TEXT_OP) {\r
7936fb6a 3171 break;\r
3172 }\r
3173\r
3174 //\r
3175 // Keep highlight on current MenuOption\r
3176 //\r
3177 Selection->QuestionId = Statement->QuestionId;\r
3178\r
3179 switch (Statement->Operand) {\r
3180 case EFI_IFR_REF_OP:\r
8ca6180f 3181 ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
7936fb6a 3182 break;\r
3183\r
3184 case EFI_IFR_ACTION_OP:\r
3185 //\r
3186 // Process the Config string <ConfigResp>\r
3187 //\r
3188 Status = ProcessQuestionConfig (Selection, Statement);\r
3189\r
3190 if (EFI_ERROR (Status)) {\r
3191 break;\r
3192 }\r
3193\r
3194 //\r
3195 // The action button may change some Question value, so refresh the form\r
3196 //\r
3197 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3198 break;\r
3199\r
3200 case EFI_IFR_RESET_BUTTON_OP:\r
3201 //\r
3202 // Reset Question to default value specified by DefaultId\r
3203 //\r
3204 ControlFlag = CfUiDefault;\r
3205 DefaultId = Statement->DefaultId;\r
3206 break;\r
3207\r
3208 default:\r
3209 //\r
3210 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
3211 //\r
8b0fc5c1 3212 UpdateKeyHelp (Selection, MenuOption, TRUE);\r
7936fb6a 3213 Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
3214\r
3215 if (EFI_ERROR (Status)) {\r
3216 Repaint = TRUE;\r
3217 NewLine = TRUE;\r
8b0fc5c1 3218 UpdateKeyHelp (Selection, MenuOption, FALSE);\r
3219 } else {\r
3220 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3221 }\r
7936fb6a 3222\r
0c66bc76
LG
3223 if (OptionString != NULL) {\r
3224 FreePool (OptionString);\r
3225 }\r
7936fb6a 3226 break;\r
3227 }\r
3228 break;\r
3229\r
3230 case CfUiReset:\r
3231 //\r
d66e6c16 3232 // We come here when someone press ESC\r
7936fb6a 3233 //\r
3234 ControlFlag = CfCheckSelection;\r
48a9d5f7 3235 FindNextMenu (Selection, &Repaint, &NewLine);\r
b18e7050 3236 break;\r
7936fb6a 3237\r
3238 case CfUiLeft:\r
3239 ControlFlag = CfCheckSelection;\r
c9325700 3240 ASSERT(MenuOption != NULL);\r
7936fb6a 3241 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3242 if (MenuOption->Sequence != 0) {\r
3243 //\r
3244 // In the middle or tail of the Date/Time op-code set, go left.\r
3245 //\r
c9325700 3246 ASSERT(NewPos != NULL);\r
7936fb6a 3247 NewPos = NewPos->BackLink;\r
3248 }\r
3249 }\r
3250 break;\r
3251\r
3252 case CfUiRight:\r
3253 ControlFlag = CfCheckSelection;\r
c9325700 3254 ASSERT(MenuOption != NULL);\r
7936fb6a 3255 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3256 if (MenuOption->Sequence != 2) {\r
3257 //\r
3258 // In the middle or tail of the Date/Time op-code set, go left.\r
3259 //\r
c9325700 3260 ASSERT(NewPos != NULL);\r
7936fb6a 3261 NewPos = NewPos->ForwardLink;\r
3262 }\r
3263 }\r
3264 break;\r
3265\r
3266 case CfUiUp:\r
3267 ControlFlag = CfCheckSelection;\r
3268\r
11232773 3269 SavedListEntry = NewPos;\r
7936fb6a 3270\r
c9325700 3271 ASSERT(NewPos != NULL);\r
11232773
LG
3272 //\r
3273 // Adjust Date/Time position before we advance forward.\r
3274 //\r
3275 AdjustDateAndTimePosition (TRUE, &NewPos);\r
ce6d12cc 3276 if (NewPos->BackLink != &gMenuOption) {\r
11232773 3277 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
715cf6dd 3278 ASSERT (MenuOption != NULL);\r
11232773
LG
3279 NewLine = TRUE;\r
3280 NewPos = NewPos->BackLink;\r
7936fb6a 3281\r
3282 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
5f4ef94a
ED
3283 if (PreviousMenuOption->Row == 0) {\r
3284 UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
3285 }\r
7936fb6a 3286 DistanceValue = PreviousMenuOption->Skip;\r
11232773
LG
3287 Difference = 0;\r
3288 if (MenuOption->Row >= DistanceValue + TopRow) {\r
5f4ef94a 3289 Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
11232773
LG
3290 }\r
3291 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3292 \r
7936fb6a 3293 if (Difference < 0) {\r
3294 //\r
11232773
LG
3295 // We hit the begining MenuOption that can be focused\r
3296 // so we simply scroll to the top.\r
7936fb6a 3297 //\r
11232773 3298 if (TopOfScreen != gMenuOption.ForwardLink) {\r
ce6d12cc 3299 TopOfScreen = gMenuOption.ForwardLink;\r
7936fb6a 3300 Repaint = TRUE;\r
11232773
LG
3301 } else {\r
3302 //\r
3303 // Scroll up to the last page when we have arrived at top page.\r
3304 //\r
3305 NewPos = &gMenuOption;\r
3306 TopOfScreen = &gMenuOption;\r
3307 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3308 ScreenOperation = UiPageUp;\r
3309 ControlFlag = CfScreenOperation;\r
3310 break;\r
7936fb6a 3311 }\r
11232773 3312 } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
1a788cdd
LG
3313 //\r
3314 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
3315 //\r
3316 TopOfScreen = NewPos;\r
3317 Repaint = TRUE;\r
3318 SkipValue = 0;\r
3319 OldSkipValue = 0;\r
11232773
LG
3320 } else if (!IsSelectable (NextMenuOption)) {\r
3321 //\r
3322 // Continue to go up until scroll to next page or the selectable option is found.\r
3323 //\r
3324 ScreenOperation = UiUp;\r
3325 ControlFlag = CfScreenOperation;\r
7936fb6a 3326 }\r
3327\r
3328 //\r
3329 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3330 //\r
3331 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
11232773
LG
3332 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3333 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
b18e7050 3334 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
7936fb6a 3335 } else {\r
11232773
LG
3336 //\r
3337 // Scroll up to the last page.\r
3338 //\r
3339 NewPos = &gMenuOption;\r
3340 TopOfScreen = &gMenuOption;\r
3341 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3342 ScreenOperation = UiPageUp;\r
3343 ControlFlag = CfScreenOperation;\r
7936fb6a 3344 }\r
3345 break;\r
3346\r
3347 case CfUiPageUp:\r
3348 ControlFlag = CfCheckSelection;\r
3349\r
c9325700 3350 ASSERT(NewPos != NULL);\r
ce6d12cc 3351 if (NewPos->BackLink == &gMenuOption) {\r
7936fb6a 3352 NewLine = FALSE;\r
3353 Repaint = FALSE;\r
3354 break;\r
3355 }\r
3356\r
3357 NewLine = TRUE;\r
3358 Repaint = TRUE;\r
3359 Link = TopOfScreen;\r
11232773 3360 Index = BottomRow;\r
ce6d12cc 3361 while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
7936fb6a 3362 Link = Link->BackLink;\r
3363 PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
5f4ef94a
ED
3364 if (PreviousMenuOption->Row == 0) {\r
3365 UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
3366 } \r
11232773
LG
3367 if (Index < PreviousMenuOption->Skip) {\r
3368 Index = 0;\r
3369 break;\r
3370 }\r
3371 Index = Index - PreviousMenuOption->Skip;\r
7936fb6a 3372 }\r
11232773
LG
3373 \r
3374 if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
3375 if (TopOfScreen == &gMenuOption) {\r
3376 TopOfScreen = gMenuOption.ForwardLink;\r
3377 NewPos = gMenuOption.BackLink;\r
5f4ef94a 3378 MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3379 Repaint = FALSE;\r
3380 } else if (TopOfScreen != Link) {\r
3381 TopOfScreen = Link;\r
3382 NewPos = Link;\r
5f4ef94a 3383 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3384 } else {\r
3385 //\r
3386 // Finally we know that NewPos is the last MenuOption can be focused.\r
3387 //\r
3388 Repaint = FALSE;\r
3389 NewPos = Link;\r
5f4ef94a 3390 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3391 }\r
3392 } else {\r
3393 if (Index + 1 < TopRow) {\r
3394 //\r
3395 // Back up the previous option.\r
3396 //\r
3397 Link = Link->ForwardLink;\r
3398 }\r
7936fb6a 3399\r
7936fb6a 3400 //\r
11232773 3401 // Move to the option in Next page.\r
7936fb6a 3402 //\r
11232773
LG
3403 if (TopOfScreen == &gMenuOption) {\r
3404 NewPos = gMenuOption.BackLink;\r
5f4ef94a 3405 MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3406 } else {\r
3407 NewPos = Link;\r
5f4ef94a 3408 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3409 }\r
3410\r
7936fb6a 3411 //\r
11232773 3412 // There are more MenuOption needing scrolling up.\r
7936fb6a 3413 //\r
11232773
LG
3414 TopOfScreen = Link;\r
3415 MenuOption = NULL;\r
7936fb6a 3416 }\r
3417\r
3418 //\r
3419 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3420 // Don't do this when we are already in the first page.\r
3421 //\r
3422 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3423 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3424 break;\r
3425\r
3426 case CfUiPageDown:\r
3427 ControlFlag = CfCheckSelection;\r
3428\r
cd7bfc2c 3429 ASSERT (NewPos != NULL);\r
ce6d12cc 3430 if (NewPos->ForwardLink == &gMenuOption) {\r
7936fb6a 3431 NewLine = FALSE;\r
3432 Repaint = FALSE;\r
3433 break;\r
3434 }\r
3435\r
3436 NewLine = TRUE;\r
3437 Repaint = TRUE;\r
3438 Link = TopOfScreen;\r
3439 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3440 Index = TopRow;\r
ce6d12cc 3441 while ((Index <= BottomRow) && (Link->ForwardLink != &gMenuOption)) {\r
7936fb6a 3442 Index = Index + NextMenuOption->Skip;\r
3443 Link = Link->ForwardLink;\r
3444 NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
3445 }\r
3446\r
11232773
LG
3447 if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
3448 //\r
3449 // Finally we know that NewPos is the last MenuOption can be focused.\r
3450 //\r
3451 Repaint = FALSE;\r
5f4ef94a 3452 MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
11232773
LG
3453 } else {\r
3454 if (Index - 1 > BottomRow) {\r
3455 //\r
3456 // Back up the previous option.\r
3457 //\r
3458 Link = Link->BackLink;\r
3459 }\r
7936fb6a 3460 //\r
11232773 3461 // There are more MenuOption needing scrolling down.\r
7936fb6a 3462 //\r
3463 TopOfScreen = Link;\r
3464 MenuOption = NULL;\r
7936fb6a 3465 //\r
11232773 3466 // Move to the option in Next page.\r
7936fb6a 3467 //\r
5f4ef94a 3468 MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
7936fb6a 3469 }\r
3470\r
3471 //\r
3472 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
3473 // Don't do this when we are already in the last page.\r
3474 //\r
11232773 3475 NewPos = Link;\r
7936fb6a 3476 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3477 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3478 break;\r
3479\r
3480 case CfUiDown:\r
3481 ControlFlag = CfCheckSelection;\r
3482 //\r
3483 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3484 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3485 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
3486 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
3487 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
3488 // the Date/Time op-code.\r
3489 //\r
3490 SavedListEntry = NewPos;\r
11232773 3491 AdjustDateAndTimePosition (FALSE, &NewPos);\r
7936fb6a 3492\r
ce6d12cc 3493 if (NewPos->ForwardLink != &gMenuOption) {\r
7936fb6a 3494 MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3495 NewLine = TRUE;\r
3496 NewPos = NewPos->ForwardLink;\r
7936fb6a 3497\r
11232773
LG
3498 Difference = 0;\r
3499 if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
5f4ef94a 3500 Difference = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
11232773
LG
3501 //\r
3502 // We hit the end of MenuOption that can be focused\r
3503 // so we simply scroll to the first page.\r
3504 //\r
3505 if (Difference < 0) {\r
3506 //\r
3507 // Scroll to the first page.\r
3508 //\r
3509 if (TopOfScreen != gMenuOption.ForwardLink) {\r
3510 TopOfScreen = gMenuOption.ForwardLink;\r
3511 Repaint = TRUE;\r
3512 MenuOption = NULL;\r
3513 } else {\r
3514 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3515 }\r
3516 NewPos = gMenuOption.ForwardLink;\r
5f4ef94a 3517 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
11232773
LG
3518 \r
3519 //\r
3520 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3521 //\r
3522 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3523 AdjustDateAndTimePosition (TRUE, &NewPos);\r
3524 break;\r
3525 }\r
3526 }\r
1a788cdd
LG
3527 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
3528\r
7936fb6a 3529 //\r
3530 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
3531 //\r
5f4ef94a 3532 UpdateOptionSkipLines (Selection, NextMenuOption);\r
11232773 3533 DistanceValue = Difference + NextMenuOption->Skip;\r
7936fb6a 3534\r
3535 Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
3536 if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
3537 (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
3538 NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
3539 ) {\r
3540 Temp ++;\r
3541 }\r
3542\r
3543 //\r
3544 // If we are going to scroll, update TopOfScreen\r
3545 //\r
3546 if (Temp > BottomRow) {\r
3547 do {\r
3548 //\r
3549 // Is the current top of screen a zero-advance op-code?\r
3550 // If so, keep moving forward till we hit a >0 advance op-code\r
3551 //\r
3552 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
3553\r
3554 //\r
3555 // If bottom op-code is more than one line or top op-code is more than one line\r
3556 //\r
3557 if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {\r
3558 //\r
3559 // Is the bottom op-code greater than or equal in size to the top op-code?\r
3560 //\r
3561 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
3562 //\r
3563 // Skip the top op-code\r
3564 //\r
3565 TopOfScreen = TopOfScreen->ForwardLink;\r
3566 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
3567\r
3568 OldSkipValue = Difference;\r
3569\r
3570 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
3571\r
3572 //\r
3573 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
3574 //\r
1a788cdd 3575 while (Difference >= (INTN) SavedMenuOption->Skip) {\r
7936fb6a 3576 //\r
3577 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
3578 //\r
1a788cdd 3579 Difference = Difference - (INTN) SavedMenuOption->Skip;\r
7936fb6a 3580 TopOfScreen = TopOfScreen->ForwardLink;\r
3581 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
7936fb6a 3582 }\r
3583 //\r
3584 // Since we will act on this op-code in the next routine, and increment the\r
3585 // SkipValue, set the skips to one less than what is required.\r
3586 //\r
3587 SkipValue = Difference - 1;\r
3588\r
3589 } else {\r
3590 //\r
3591 // Since we will act on this op-code in the next routine, and increment the\r
3592 // SkipValue, set the skips to one less than what is required.\r
3593 //\r
3594 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
3595 }\r
3596 } else {\r
3597 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
3598 TopOfScreen = TopOfScreen->ForwardLink;\r
3599 break;\r
3600 } else {\r
3601 SkipValue = OldSkipValue;\r
3602 }\r
3603 }\r
3604 //\r
3605 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
3606 // Let's set a skip flag to smoothly scroll the top of the screen.\r
3607 //\r
3608 if (SavedMenuOption->Skip > 1) {\r
3609 if (SavedMenuOption == NextMenuOption) {\r
3610 SkipValue = 0;\r
3611 } else {\r
3612 SkipValue++;\r
3613 }\r
1a788cdd
LG
3614 } else if (SavedMenuOption->Skip == 1) {\r
3615 SkipValue = 0;\r
7936fb6a 3616 } else {\r
3617 SkipValue = 0;\r
3618 TopOfScreen = TopOfScreen->ForwardLink;\r
3619 }\r
3620 } while (SavedMenuOption->Skip == 0);\r
3621\r
3622 Repaint = TRUE;\r
3623 OldSkipValue = SkipValue;\r
11232773
LG
3624 } else if (!IsSelectable (NextMenuOption)) {\r
3625 //\r
3626 // Continue to go down until scroll to next page or the selectable option is found.\r
3627 //\r
3628 ScreenOperation = UiDown;\r
3629 ControlFlag = CfScreenOperation;\r
7936fb6a 3630 }\r
3631\r
3632 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3633\r
b18e7050 3634 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
7936fb6a 3635\r
3636 } else {\r
7936fb6a 3637 //\r
11232773 3638 // Scroll to the first page.\r
7936fb6a 3639 //\r
11232773
LG
3640 if (TopOfScreen != gMenuOption.ForwardLink) {\r
3641 TopOfScreen = gMenuOption.ForwardLink;\r
3642 Repaint = TRUE;\r
3643 MenuOption = NULL;\r
3644 } else {\r
3645 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
3646 }\r
3647 NewLine = TRUE;\r
3648 NewPos = gMenuOption.ForwardLink;\r
5f4ef94a 3649 MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
7936fb6a 3650 }\r
11232773
LG
3651\r
3652 //\r
3653 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
3654 //\r
3655 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
3656 AdjustDateAndTimePosition (TRUE, &NewPos);\r
7936fb6a 3657 break;\r
3658\r
48a9d5f7 3659 case CfUiHotKey:\r
7936fb6a 3660 ControlFlag = CfCheckSelection;\r
48a9d5f7
LG
3661 \r
3662 Status = EFI_SUCCESS;\r
7936fb6a 3663 //\r
48a9d5f7 3664 // Discard changes. After it, no NV flag is showed.\r
7936fb6a 3665 //\r
48a9d5f7
LG
3666 if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
3667 Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3668 if (!EFI_ERROR (Status)) {\r
3669 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3670 Selection->Statement = NULL;\r
3671 gResetRequired = FALSE;\r
3672 } else {\r
3673 do {\r
3674 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString);\r
3675 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3676 //\r
3677 // Still show current page.\r
3678 //\r
3679 Selection->Action = UI_ACTION_NONE;\r
3680 Repaint = TRUE;\r
3681 NewLine = TRUE;\r
3682 break;\r
3683 }\r
3684 }\r
7936fb6a 3685\r
48a9d5f7
LG
3686 //\r
3687 // Reterieve default setting. After it. NV flag will be showed.\r
3688 //\r
3689 if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
3690 Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope);\r
3691 if (!EFI_ERROR (Status)) {\r
3692 Selection->Action = UI_ACTION_REFRESH_FORM;\r
3693 Selection->Statement = NULL;\r
3694 gResetRequired = TRUE;\r
3695 } else {\r
3696 do {\r
3697 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString);\r
3698 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3699 //\r
3700 // Still show current page.\r
3701 //\r
3702 Selection->Action = UI_ACTION_NONE;\r
3703 Repaint = TRUE;\r
3704 NewLine = TRUE;\r
3705 break;\r
3706 }\r
3707 }\r
7936fb6a 3708\r
48a9d5f7
LG
3709 //\r
3710 // Save changes. After it, no NV flag is showed.\r
3711 //\r
3712 if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
3713 Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3714 if (!EFI_ERROR (Status)) {\r
3715 ASSERT(MenuOption != NULL);\r
3716 UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3717 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
3718 } else {\r
3719 do {\r
3720 CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString);\r
3721 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
3722 //\r
3723 // Still show current page.\r
3724 //\r
3725 Selection->Action = UI_ACTION_NONE;\r
3726 Repaint = TRUE;\r
3727 NewLine = TRUE;\r
3728 break;\r
3729 }\r
3730 }\r
3731 \r
3732 //\r
3733 // Set Reset required Flag\r
3734 //\r
3735 if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
3736 gResetRequired = TRUE;\r
3737 }\r
3738 \r
3739 //\r
3740 // Exit Action\r
3741 //\r
3742 if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
3743 //\r
3744 // Form Exit without saving, Similar to ESC Key.\r
3745 // FormSet Exit without saving, Exit SendForm.\r
3746 // System Exit without saving, CallExitHandler and Exit SendForm.\r
3747 //\r
3748 DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
3749 if (gBrowserSettingScope == FormLevel) {\r
3750 ControlFlag = CfUiReset;\r
3751 } else if (gBrowserSettingScope == FormSetLevel) {\r
3752 Selection->Action = UI_ACTION_EXIT;\r
3753 } else if (gBrowserSettingScope == SystemLevel) {\r
3754 if (ExitHandlerFunction != NULL) {\r
3755 ExitHandlerFunction ();\r
3756 }\r
3757 Selection->Action = UI_ACTION_EXIT;\r
3758 }\r
3759 Selection->Statement = NULL;\r
7936fb6a 3760 }\r
3761 break;\r
3762\r
3763 case CfUiDefault:\r
3764 ControlFlag = CfCheckSelection;\r
4f33c838 3765 //\r
48a9d5f7 3766 // Reset to default value for all forms in the whole system.\r
4f33c838 3767 //\r
48a9d5f7 3768 Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel);\r
7936fb6a 3769\r
3770 if (!EFI_ERROR (Status)) {\r
3771 Selection->Action = UI_ACTION_REFRESH_FORM;\r
ebe43565 3772 Selection->Statement = NULL;\r
15713670 3773 gResetRequired = TRUE;\r
7936fb6a 3774 }\r
3775 break;\r
3776\r
3777 case CfUiNoOperation:\r
3778 ControlFlag = CfCheckSelection;\r
3779 break;\r
3780\r
3781 case CfExit:\r
3782 UiFreeRefreshList ();\r
3783\r
3784 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
3785 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3786 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3787 gST->ConOut->OutputString (gST->ConOut, L"\n");\r
3788\r
3789 return EFI_SUCCESS;\r
3790\r
3791 default:\r
3792 break;\r
3793 }\r
3794 }\r
3795}\r