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