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