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