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