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