]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c
Modules clean up.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / SetupBrowserDxe / Ui.c
CommitLineData
103b6520 1/**@file\r
2 Implementation for UI.\r
3\r
4Copyright (c) 2006 - 2007, Intel Corporation\r
5All rights reserved. This program and the accompanying materials\r
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
103b6520 15\r
16#include "Setup.h"\r
17#include "Ui.h"\r
18#include "Colors.h"\r
19\r
20//\r
21// Implementation\r
22//\r
23VOID\r
24SetUnicodeMem (\r
25 IN VOID *Buffer,\r
26 IN UINTN Size,\r
27 IN CHAR16 Value\r
28 )\r
29/*++\r
30\r
31Routine Description:\r
32\r
33 Set Buffer to Value for Size bytes.\r
34\r
35Arguments:\r
36\r
37 Buffer - Memory to set.\r
38\r
39 Size - Number of bytes to set\r
40\r
41 Value - Value of the set operation.\r
42\r
43Returns:\r
44\r
45 None\r
46\r
47--*/\r
48{\r
49 CHAR16 *Ptr;\r
50\r
51 Ptr = Buffer;\r
52 while (Size--) {\r
53 *(Ptr++) = Value;\r
54 }\r
55}\r
56\r
57VOID\r
58UiInitMenu (\r
59 VOID\r
60 )\r
61/*++\r
62\r
63Routine Description:\r
64 Initialize Menu option list.\r
65\r
66Arguments:\r
67\r
68Returns:\r
69\r
70--*/\r
71{\r
72 InitializeListHead (&Menu);\r
73}\r
74\r
75VOID\r
76UiInitMenuList (\r
77 VOID\r
78 )\r
79/*++\r
80\r
81Routine Description:\r
82 Initialize Menu option list.\r
83\r
84Arguments:\r
85\r
86Returns:\r
87\r
88--*/\r
89{\r
90 InitializeListHead (&gMenuList);\r
91}\r
92\r
93VOID\r
94UiRemoveMenuListEntry (\r
95 IN UI_MENU_OPTION *Selection,\r
96 OUT UI_MENU_OPTION **PreviousSelection\r
97 )\r
98/*++\r
99\r
100Routine Description:\r
101 Remove Menu option list.\r
102\r
103Arguments:\r
104\r
105Returns:\r
106\r
107--*/\r
108{\r
109 UI_MENU_LIST *UiMenuList;\r
110\r
111 *PreviousSelection = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
112 ASSERT (*PreviousSelection != NULL);\r
113\r
114 if (!IsListEmpty (&gMenuList)) {\r
115 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
116 (*PreviousSelection)->IfrNumber = UiMenuList->Selection.IfrNumber;\r
117 (*PreviousSelection)->FormId = UiMenuList->Selection.FormId;\r
118 (*PreviousSelection)->Tags = UiMenuList->Selection.Tags;\r
119 (*PreviousSelection)->ThisTag = UiMenuList->Selection.ThisTag;\r
120 (*PreviousSelection)->Handle = UiMenuList->Selection.Handle;\r
121 gEntryNumber = UiMenuList->FormerEntryNumber;\r
122 RemoveEntryList (&UiMenuList->MenuLink);\r
123 FreePool (UiMenuList);\r
124 }\r
125}\r
126\r
127VOID\r
128UiFreeMenuList (\r
129 VOID\r
130 )\r
131/*++\r
132\r
133Routine Description:\r
134 Free Menu option linked list.\r
135\r
136Arguments:\r
137\r
138Returns:\r
139\r
140--*/\r
141{\r
142 UI_MENU_LIST *UiMenuList;\r
143\r
144 while (!IsListEmpty (&gMenuList)) {\r
145 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
146 RemoveEntryList (&UiMenuList->MenuLink);\r
147 FreePool (UiMenuList);\r
148 }\r
149}\r
150\r
151VOID\r
152UiAddMenuListEntry (\r
153 IN UI_MENU_OPTION *Selection\r
154 )\r
155/*++\r
156\r
157Routine Description:\r
158 Add one menu entry to the linked lst\r
159\r
160Arguments:\r
161\r
162Returns:\r
163\r
164--*/\r
165{\r
166 UI_MENU_LIST *UiMenuList;\r
167\r
168 UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
169 ASSERT (UiMenuList != NULL);\r
170\r
171 UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
172 CopyMem (&UiMenuList->Selection, Selection, sizeof (UI_MENU_OPTION));\r
173\r
174 InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
175}\r
176\r
177VOID\r
178UiFreeMenu (\r
179 VOID\r
180 )\r
181/*++\r
182\r
183Routine Description:\r
184 Free Menu option linked list.\r
185\r
186Arguments:\r
187\r
188Returns:\r
189\r
190--*/\r
191{\r
192 UI_MENU_OPTION *MenuOption;\r
193\r
194 while (!IsListEmpty (&Menu)) {\r
195 MenuOption = CR (Menu.ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
196 RemoveEntryList (&MenuOption->Link);\r
197\r
198 //\r
199 // We allocated space for this description when we did a GetToken, free it here\r
200 //\r
201 FreePool (MenuOption->Description);\r
202 FreePool (MenuOption);\r
203 }\r
204}\r
205\r
206STATIC\r
207VOID\r
208UpdateDateAndTime (\r
209 VOID\r
210 )\r
211/*++\r
212\r
213Routine Description:\r
214 Refresh screen with current date and/or time based on screen context\r
215\r
216Arguments:\r
217\r
218Returns:\r
219\r
220--*/\r
221{\r
222 CHAR16 *OptionString;\r
223 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
224 UINTN Index;\r
225 UINTN Loop;\r
226\r
227 OptionString = NULL;\r
228\r
229 if (gMenuRefreshHead != NULL) {\r
230\r
231 MenuRefreshEntry = gMenuRefreshHead;\r
232\r
233 do {\r
234 gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
235 ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &OptionString);\r
236\r
237 if (OptionString != NULL) {\r
238 //\r
239 // If leading spaces on OptionString - remove the spaces\r
240 //\r
241 for (Index = 0; OptionString[Index] == L' '; Index++)\r
242 ;\r
243\r
244 for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
245 OptionString[Loop] = OptionString[Index];\r
246 Loop++;\r
247 }\r
248\r
249 OptionString[Loop] = CHAR_NULL;\r
250\r
251 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
252 }\r
253\r
254 MenuRefreshEntry = MenuRefreshEntry->Next;\r
255\r
256 } while (MenuRefreshEntry != NULL);\r
257 }\r
258\r
259 if (OptionString != NULL) {\r
260 FreePool (OptionString);\r
261 }\r
262}\r
263\r
264EFI_STATUS\r
265UiWaitForSingleEvent (\r
266 IN EFI_EVENT Event,\r
267 IN UINT64 Timeout OPTIONAL\r
268 )\r
269/*++\r
270\r
271Routine Description:\r
272 Wait for a given event to fire, or for an optional timeout to expire.\r
273\r
274Arguments:\r
275 Event - The event to wait for\r
276\r
277 Timeout - An optional timeout value in 100 ns units.\r
278\r
279Returns:\r
280\r
281 EFI_SUCCESS - Event fired before Timeout expired.\r
282 EFI_TIME_OUT - Timout expired before Event fired.\r
283\r
284--*/\r
285{\r
286 EFI_STATUS Status;\r
287 UINTN Index;\r
288 EFI_EVENT TimerEvent;\r
289 EFI_EVENT WaitList[2];\r
290\r
291 if (Timeout) {\r
292 //\r
293 // Create a timer event\r
294 //\r
295 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
296 if (!EFI_ERROR (Status)) {\r
297 //\r
298 // Set the timer event\r
299 //\r
300 gBS->SetTimer (\r
301 TimerEvent,\r
302 TimerRelative,\r
303 Timeout\r
304 );\r
305\r
306 //\r
307 // Wait for the original event or the timer\r
308 //\r
309 WaitList[0] = Event;\r
310 WaitList[1] = TimerEvent;\r
311 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
312 gBS->CloseEvent (TimerEvent);\r
313\r
314 //\r
315 // If the timer expired, change the return to timed out\r
316 //\r
317 if (!EFI_ERROR (Status) && Index == 1) {\r
318 Status = EFI_TIMEOUT;\r
319 }\r
320 }\r
321 } else {\r
322 //\r
323 // Update screen every second\r
324 //\r
325 Timeout = ONE_SECOND;\r
326\r
327 do {\r
328 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
329\r
330 //\r
331 // Set the timer event\r
332 //\r
333 gBS->SetTimer (\r
334 TimerEvent,\r
335 TimerRelative,\r
336 Timeout\r
337 );\r
338\r
339 //\r
340 // Wait for the original event or the timer\r
341 //\r
342 WaitList[0] = Event;\r
343 WaitList[1] = TimerEvent;\r
344 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
345\r
346 //\r
347 // If the timer expired, update anything that needs a refresh and keep waiting\r
348 //\r
349 if (!EFI_ERROR (Status) && Index == 1) {\r
350 Status = EFI_TIMEOUT;\r
351 UpdateDateAndTime ();\r
352 }\r
353\r
354 gBS->CloseEvent (TimerEvent);\r
355 } while (Status == EFI_TIMEOUT);\r
356 }\r
357\r
358 return Status;\r
359}\r
360\r
361VOID\r
362UiAddMenuOption (\r
363 IN CHAR16 *String,\r
364 IN EFI_HII_HANDLE Handle,\r
365 IN EFI_TAG *Tags,\r
366 IN VOID *FormBinary,\r
367 IN UINTN IfrNumber\r
368 )\r
369/*++\r
370\r
371Routine Description:\r
372 Add one menu option by specified description and context.\r
373\r
374Arguments:\r
375 String - String description for this option.\r
376 Context - Context data for entry.\r
377\r
378Returns:\r
379\r
380--*/\r
381{\r
382 UI_MENU_OPTION *MenuOption;\r
383\r
384 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
385 ASSERT (MenuOption);\r
386\r
387 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
388 MenuOption->Description = String;\r
389 MenuOption->Handle = Handle;\r
390 MenuOption->FormBinary = FormBinary;\r
391 MenuOption->IfrNumber = IfrNumber;\r
392 MenuOption->Skip = 1;\r
393 MenuOption->Tags = Tags;\r
394 MenuOption->TagIndex = 0;\r
395 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);\r
396 MenuOption->EntryNumber = (UINT16) IfrNumber;\r
397\r
398 InsertTailList (&Menu, &MenuOption->Link);\r
399}\r
400\r
401VOID\r
402UiAddSubMenuOption (\r
403 IN CHAR16 *String,\r
404 IN EFI_HII_HANDLE Handle,\r
405 IN EFI_TAG *Tags,\r
406 IN UINTN TagIndex,\r
407 IN UINT16 FormId,\r
408 IN UINT16 MenuItemCount\r
409 )\r
410/*++\r
411\r
412Routine Description:\r
413 Add one menu option by specified description and context.\r
414\r
415Arguments:\r
416 String - String description for this option.\r
417 Context - Context data for entry.\r
418\r
419Returns:\r
420\r
421--*/\r
422{\r
423 UI_MENU_OPTION *MenuOption;\r
424\r
425 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
426 ASSERT (MenuOption);\r
427\r
428 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
429 MenuOption->Description = String;\r
430 MenuOption->Handle = Handle;\r
431 MenuOption->Skip = Tags[TagIndex].NumberOfLines;\r
432 MenuOption->IfrNumber = gActiveIfr;\r
433 MenuOption->Tags = Tags;\r
434 MenuOption->TagIndex = TagIndex;\r
435 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);\r
436 MenuOption->Consistency = Tags[TagIndex].Consistency;\r
437 MenuOption->FormId = FormId;\r
438 MenuOption->GrayOut = Tags[TagIndex].GrayOut;\r
439 MenuOption->EntryNumber = MenuItemCount;\r
440\r
441 InsertTailList (&Menu, &MenuOption->Link);\r
442}\r
443\r
444EFI_STATUS\r
445CreateDialog (\r
446 IN UINTN NumberOfLines,\r
447 IN BOOLEAN HotKey,\r
448 IN UINTN MaximumStringSize,\r
449 OUT CHAR16 *StringBuffer,\r
450 OUT EFI_INPUT_KEY *KeyValue,\r
451 IN CHAR16 *String,\r
452 ...\r
453 )\r
454/*++\r
455\r
456Routine Description:\r
457 Routine used to abstract a generic dialog interface and return the selected key or string\r
458\r
459Arguments:\r
460 NumberOfLines - The number of lines for the dialog box\r
461 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue\r
462 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and\r
463 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns\r
464 MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes\r
465 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE\r
466 KeyValue - The EFI_KEY value returned if HotKey is TRUE..\r
467 String - Pointer to the first string in the list\r
468 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box\r
469\r
470Returns:\r
471 EFI_SUCCESS - Displayed dialog and received user interaction\r
472 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))\r
473 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine\r
474\r
475--*/\r
476{\r
477 VA_LIST Marker;\r
478 UINTN Count;\r
479 EFI_INPUT_KEY Key;\r
480 UINTN LargestString;\r
481 CHAR16 *TempString;\r
482 CHAR16 *BufferedString;\r
483 CHAR16 *StackString;\r
484 CHAR16 KeyPad[2];\r
485 UINTN Start;\r
486 UINTN Top;\r
487 UINTN Index;\r
488 BOOLEAN SelectionComplete;\r
489 UINTN InputOffset;\r
490 UINTN CurrentAttribute;\r
491 UINTN DimensionsWidth;\r
492 UINTN DimensionsHeight;\r
493\r
494 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
495 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
496\r
497 SelectionComplete = FALSE;\r
498 InputOffset = 0;\r
499 TempString = AllocateZeroPool (MaximumStringSize * 2);\r
500 BufferedString = AllocateZeroPool (MaximumStringSize * 2);\r
501 CurrentAttribute = gST->ConOut->Mode->Attribute;\r
502\r
503 ASSERT (TempString);\r
504 ASSERT (BufferedString);\r
505\r
506 VA_START (Marker, String);\r
507\r
508 //\r
509 // Zero the outgoing buffer\r
510 //\r
511 ZeroMem (StringBuffer, MaximumStringSize);\r
512\r
513 if (HotKey) {\r
514 if (KeyValue == NULL) {\r
515 return EFI_INVALID_PARAMETER;\r
516 }\r
517 } else {\r
518 if (StringBuffer == NULL) {\r
519 return EFI_INVALID_PARAMETER;\r
520 }\r
521 }\r
522 //\r
523 // Disable cursor\r
524 //\r
525 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
526\r
527 LargestString = (GetStringWidth (String) / 2);\r
528\r
529 if (LargestString == L' ') {\r
530 InputOffset = 1;\r
531 }\r
532 //\r
533 // Determine the largest string in the dialog box\r
534 // Notice we are starting with 1 since String is the first string\r
535 //\r
536 for (Count = 1; Count < NumberOfLines; Count++) {\r
537 StackString = VA_ARG (Marker, CHAR16 *);\r
538\r
539 if (StackString[0] == L' ') {\r
540 InputOffset = Count + 1;\r
541 }\r
542\r
543 if ((GetStringWidth (StackString) / 2) > LargestString) {\r
544 //\r
545 // Size of the string visually and subtract the width by one for the null-terminator\r
546 //\r
547 LargestString = (GetStringWidth (StackString) / 2);\r
548 }\r
549 }\r
550\r
551 Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
552 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
553\r
554 Count = 0;\r
555\r
556 //\r
557 // Display the Popup\r
558 //\r
559 CreateSharedPopUp (LargestString, NumberOfLines, &String);\r
560\r
561 //\r
562 // Take the first key typed and report it back?\r
563 //\r
564 if (HotKey) {\r
565 WaitForKeyStroke (&Key);\r
566 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
567\r
568 } else {\r
569 do {\r
570 WaitForKeyStroke (&Key);\r
571\r
572 switch (Key.UnicodeChar) {\r
573 case CHAR_NULL:\r
574 switch (Key.ScanCode) {\r
575 case SCAN_ESC:\r
576 FreePool (TempString);\r
577 FreePool (BufferedString);\r
578 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
579 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
580 return EFI_DEVICE_ERROR;\r
581\r
582 default:\r
583 break;\r
584 }\r
585\r
586 break;\r
587\r
588 case CHAR_CARRIAGE_RETURN:\r
589 SelectionComplete = TRUE;\r
590 FreePool (TempString);\r
591 FreePool (BufferedString);\r
592 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
593 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
594 return EFI_SUCCESS;\r
595 break;\r
596\r
597 case CHAR_BACKSPACE:\r
598 if (StringBuffer[0] != CHAR_NULL) {\r
599 for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
600 TempString[Index] = StringBuffer[Index];\r
601 }\r
602 //\r
603 // Effectively truncate string by 1 character\r
604 //\r
605 TempString[Index - 1] = CHAR_NULL;\r
606 StrCpy (StringBuffer, TempString);\r
607 }\r
608\r
609 default:\r
610 //\r
611 // If it is the beginning of the string, don't worry about checking maximum limits\r
612 //\r
613 if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
614 StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
615 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
616 } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
617 KeyPad[0] = Key.UnicodeChar;\r
618 KeyPad[1] = CHAR_NULL;\r
619 StrCat (StringBuffer, KeyPad);\r
620 StrCat (TempString, KeyPad);\r
621 }\r
622 //\r
623 // If the width of the input string is now larger than the screen, we nee to\r
624 // adjust the index to start printing portions of the string\r
625 //\r
626 SetUnicodeMem (BufferedString, LargestString, L' ');\r
627\r
628 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
629\r
630 if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
631 Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
632 } else {\r
633 Index = 0;\r
634 }\r
635\r
636 for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
637 BufferedString[Count] = StringBuffer[Index];\r
638 }\r
639\r
640 PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
641 break;\r
642 }\r
643 } while (!SelectionComplete);\r
644 }\r
645\r
646 gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
647 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
648 return EFI_SUCCESS;\r
649}\r
650\r
651VOID\r
652CreateSharedPopUp (\r
653 IN UINTN RequestedWidth,\r
654 IN UINTN NumberOfLines,\r
655 IN CHAR16 **ArrayOfStrings\r
656 )\r
657{\r
658 UINTN Index;\r
659 UINTN Count;\r
660 CHAR16 Character;\r
661 UINTN Start;\r
662 UINTN End;\r
663 UINTN Top;\r
664 UINTN Bottom;\r
665 CHAR16 *String;\r
666\r
667 UINTN DimensionsWidth;\r
668 UINTN DimensionsHeight;\r
669\r
670 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
671 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
672\r
673 Count = 0;\r
674\r
675 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
676\r
677 if ((RequestedWidth + 2) > DimensionsWidth) {\r
678 RequestedWidth = DimensionsWidth - 2;\r
679 }\r
680 //\r
681 // Subtract the PopUp width from total Columns, allow for one space extra on\r
682 // each end plus a border.\r
683 //\r
684 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
685 End = Start + RequestedWidth + 1;\r
686\r
687 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
688 Bottom = Top + NumberOfLines + 2;\r
689\r
690 Character = (CHAR16) BOXDRAW_DOWN_RIGHT;\r
691 PrintCharAt (Start, Top, Character);\r
692 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
693 for (Index = Start; Index + 2 < End; Index++) {\r
694 PrintChar (Character);\r
695 }\r
696\r
697 Character = (CHAR16) BOXDRAW_DOWN_LEFT;\r
698 PrintChar (Character);\r
699 Character = (CHAR16) BOXDRAW_VERTICAL;\r
700 for (Index = Top; Index + 2 < Bottom; Index++) {\r
701 String = ArrayOfStrings[Count];\r
702 Count++;\r
703\r
704 //\r
705 // This will clear the background of the line - we never know who might have been\r
706 // here before us. This differs from the next clear in that it used the non-reverse\r
707 // video for normal printing.\r
708 //\r
709 if (GetStringWidth (String) / 2 > 1) {\r
710 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
711 }\r
712 //\r
713 // Passing in a space results in the assumption that this is where typing will occur\r
714 //\r
715 if (String[0] == L' ') {\r
716 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
717 }\r
718 //\r
719 // Passing in a NULL results in a blank space\r
720 //\r
721 if (String[0] == CHAR_NULL) {\r
722 ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
723 }\r
724\r
725 PrintStringAt (\r
726 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
727 Index + 1,\r
728 String\r
729 );\r
730 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
731 PrintCharAt (Start, Index + 1, Character);\r
732 PrintCharAt (End - 1, Index + 1, Character);\r
733 }\r
734\r
735 Character = (CHAR16) BOXDRAW_UP_RIGHT;\r
736 PrintCharAt (Start, Bottom - 1, Character);\r
737 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
738 for (Index = Start; Index + 2 < End; Index++) {\r
739 PrintChar (Character);\r
740 }\r
741\r
742 Character = (CHAR16) BOXDRAW_UP_LEFT;\r
743 PrintChar (Character);\r
744}\r
745\r
746VOID\r
747CreatePopUp (\r
748 IN UINTN RequestedWidth,\r
749 IN UINTN NumberOfLines,\r
750 IN CHAR16 *ArrayOfStrings,\r
751 ...\r
752 )\r
753{\r
754 CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);\r
755}\r
756\r
757VOID\r
758UpdateStatusBar (\r
759 IN UINTN MessageType,\r
760 IN UINT8 Flags,\r
761 IN BOOLEAN State\r
762 )\r
763{\r
764 UINTN Index;\r
765 STATIC BOOLEAN InputError;\r
766 CHAR16 *NvUpdateMessage;\r
767 CHAR16 *InputErrorMessage;\r
768\r
769 NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
770 InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
771\r
772 switch (MessageType) {\r
773 case INPUT_ERROR:\r
774 if (State) {\r
775 gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
776 PrintStringAt (\r
777 gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
778 gScreenDimensions.BottomRow - 1,\r
779 InputErrorMessage\r
780 );\r
781 InputError = TRUE;\r
782 } else {\r
783 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
784 for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
785 PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, (CHAR16 *) L" ");\r
786 }\r
787\r
788 InputError = FALSE;\r
789 }\r
790 break;\r
791\r
792 case NV_UPDATE_REQUIRED:\r
793 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
794 if (State) {\r
795 gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
796 PrintStringAt (\r
797 gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
798 gScreenDimensions.BottomRow - 1,\r
799 NvUpdateMessage\r
800 );\r
801 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
802\r
803 gNvUpdateRequired = TRUE;\r
804 } else {\r
805 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
806 for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
807 PrintAt (\r
808 (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
809 gScreenDimensions.BottomRow - 1,\r
810 (CHAR16 *) L" "\r
811 );\r
812 }\r
813\r
814 gNvUpdateRequired = FALSE;\r
815 }\r
816 }\r
817 break;\r
818\r
819 case REFRESH_STATUS_BAR:\r
820 if (InputError) {\r
821 UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
822 }\r
823\r
824 if (gNvUpdateRequired) {\r
825 UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
826 }\r
827 break;\r
828\r
829 default:\r
830 break;\r
831 }\r
832\r
833 FreePool (InputErrorMessage);\r
834 FreePool (NvUpdateMessage);\r
835 return ;\r
836}\r
837\r
838VOID\r
839FreeData (\r
840 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
841 IN CHAR16 *FormattedString,\r
842 IN CHAR16 *OptionString\r
843 )\r
844/*++\r
845\r
846Routine Description:\r
847\r
848 Used to remove the allocated data instances\r
849\r
850Arguments:\r
851\r
852Returns:\r
853\r
854--*/\r
855{\r
856 EFI_FILE_FORM_TAGS *FileForm;\r
857 EFI_FILE_FORM_TAGS *PreviousFileForm;\r
858 EFI_FORM_TAGS *FormTags;\r
859 EFI_FORM_TAGS *PreviousFormTags;\r
860 EFI_IFR_BINARY *IfrBinary;\r
861 EFI_IFR_BINARY *PreviousIfrBinary;\r
862 EFI_INCONSISTENCY_DATA *Inconsistent;\r
863 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
864 EFI_VARIABLE_DEFINITION *PreviousVariableDefinition;\r
865 VOID *Buffer;\r
866 UINTN Index;\r
867\r
868 FileForm = FileFormTagsHead;\r
869\r
870 if (FormattedString != NULL) {\r
871 FreePool (FormattedString);\r
872 }\r
873\r
874 if (OptionString != NULL) {\r
875 FreePool (OptionString);\r
876 }\r
877\r
878 for (; FileForm != NULL;) {\r
879 PreviousFileForm = NULL;\r
880\r
881 //\r
882 // Advance FileForm to the last entry\r
883 //\r
884 for (; FileForm->NextFile != NULL; FileForm = FileForm->NextFile) {\r
885 PreviousFileForm = FileForm;\r
886 }\r
887\r
888 FormTags = &FileForm->FormTags;\r
889\r
890 for (; FormTags != NULL;) {\r
891 FormTags = &FileForm->FormTags;\r
892 PreviousFormTags = NULL;\r
893\r
894 //\r
895 // Advance FormTags to the last entry\r
896 //\r
897 for (; FormTags->Next != NULL; FormTags = FormTags->Next) {\r
898 PreviousFormTags = FormTags;\r
899 }\r
900 //\r
901 // Walk through each of the tags and free the IntList allocation\r
902 //\r
903 for (Index = 0; FormTags->Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {\r
904 //\r
905 // It is more than likely that the very last page will contain an end formset\r
906 //\r
907 if (FormTags->Tags[Index].Operand == EFI_IFR_END_FORM_SET_OP) {\r
908 break;\r
909 }\r
910\r
911 if (FormTags->Tags[Index].IntList != NULL) {\r
912 FreePool (FormTags->Tags[Index].IntList);\r
913 }\r
914 }\r
915\r
916 if (PreviousFormTags != NULL) {\r
917 FreePool (FormTags->Tags);\r
918 FormTags = PreviousFormTags;\r
919 FreePool (FormTags->Next);\r
920 FormTags->Next = NULL;\r
921 } else {\r
922 FreePool (FormTags->Tags);\r
923 FormTags = NULL;\r
924 }\r
925 }\r
926 //\r
927 // Last FileForm entry's Inconsistent database\r
928 //\r
929 Inconsistent = FileForm->InconsistentTags;\r
930\r
931 //\r
932 // Advance Inconsistent to the last entry\r
933 //\r
934 for (; Inconsistent->Next != NULL; Inconsistent = Inconsistent->Next)\r
935 ;\r
936\r
937 for (; Inconsistent != NULL;) {\r
938 //\r
939 // Preserve the Previous pointer\r
940 //\r
941 Buffer = (VOID *) Inconsistent->Previous;\r
942\r
943 //\r
944 // Free the current entry\r
945 //\r
946 FreePool (Inconsistent);\r
947\r
948 //\r
949 // Restore the Previous pointer\r
950 //\r
951 Inconsistent = (EFI_INCONSISTENCY_DATA *) Buffer;\r
952 }\r
953\r
954 VariableDefinition = FileForm->VariableDefinitions;\r
955\r
956 for (; VariableDefinition != NULL;) {\r
957 VariableDefinition = FileForm->VariableDefinitions;\r
958 PreviousVariableDefinition = NULL;\r
959\r
960 //\r
961 // Advance VariableDefinitions to the last entry\r
962 //\r
963 for (; VariableDefinition->Next != NULL; VariableDefinition = VariableDefinition->Next) {\r
964 PreviousVariableDefinition = VariableDefinition;\r
965 }\r
966\r
967 FreePool (VariableDefinition->VariableName);\r
968\r
969 if (VariableDefinition->NvRamMap != NULL) {\r
970 FreePool (VariableDefinition->NvRamMap);\r
971 }\r
972\r
973 if (VariableDefinition->FakeNvRamMap != NULL) {\r
974 FreePool (VariableDefinition->FakeNvRamMap);\r
975 }\r
976\r
977 if (PreviousVariableDefinition != NULL) {\r
978 VariableDefinition = PreviousVariableDefinition;\r
979 FreePool (VariableDefinition->Next);\r
980 VariableDefinition->Next = NULL;\r
981 } else {\r
982 FreePool (VariableDefinition);\r
983 VariableDefinition = NULL;\r
984 }\r
985 }\r
986\r
987 if (PreviousFileForm != NULL) {\r
988 FileForm = PreviousFileForm;\r
989 FreePool (FileForm->NextFile);\r
990 FileForm->NextFile = NULL;\r
991 } else {\r
992 FreePool (FileForm);\r
993 FileForm = NULL;\r
994 }\r
995 }\r
996\r
997 IfrBinary = gBinaryDataHead;\r
998\r
999 for (; IfrBinary != NULL;) {\r
1000 IfrBinary = gBinaryDataHead;\r
1001 PreviousIfrBinary = NULL;\r
1002\r
1003 //\r
1004 // Advance IfrBinary to the last entry\r
1005 //\r
1006 for (; IfrBinary->Next != NULL; IfrBinary = IfrBinary->Next) {\r
1007 PreviousIfrBinary = IfrBinary;\r
1008 }\r
1009\r
1010 FreePool (IfrBinary->IfrPackage);\r
1011\r
1012 if (PreviousIfrBinary != NULL) {\r
1013 IfrBinary = PreviousIfrBinary;\r
1014 FreePool (IfrBinary->Next);\r
1015 IfrBinary->Next = NULL;\r
1016 } else {\r
1017 FreePool (IfrBinary);\r
1018 IfrBinary = NULL;\r
1019 }\r
1020 }\r
1021\r
1022 FreePool (gPreviousValue);\r
1023 gPreviousValue = NULL;\r
1024\r
1025 //\r
1026 // Free Browser Strings\r
1027 //\r
1028 FreePool (gPressEnter);\r
1029 FreePool (gConfirmError);\r
1030 FreePool (gConfirmPassword);\r
1031 FreePool (gPromptForNewPassword);\r
1032 FreePool (gPromptForPassword);\r
1033 FreePool (gToggleCheckBox);\r
1034 FreePool (gNumericInput);\r
1035 FreePool (gMakeSelection);\r
1036 FreePool (gMoveHighlight);\r
1037 FreePool (gEscapeString);\r
1038 FreePool (gEnterCommitString);\r
1039 FreePool (gEnterString);\r
1040 FreePool (gFunctionOneString);\r
1041 FreePool (gFunctionTwoString);\r
1042 FreePool (gFunctionNineString);\r
1043 FreePool (gFunctionTenString);\r
1044 return ;\r
1045}\r
1046\r
1047STATIC\r
1048BOOLEAN\r
1049SelectionsAreValid (\r
1050 IN UI_MENU_OPTION *MenuOption,\r
1051 IN EFI_FILE_FORM_TAGS *FileFormTagsHead\r
1052 )\r
1053/*++\r
1054\r
1055Routine Description:\r
1056 Initiate late consistency checks against the current page.\r
1057\r
1058Arguments:\r
1059 None\r
1060\r
1061Returns:\r
1062\r
1063--*/\r
1064{\r
1065 LIST_ENTRY *Link;\r
1066 EFI_TAG *Tag;\r
1067 EFI_FILE_FORM_TAGS *FileFormTags;\r
1068 CHAR16 *StringPtr;\r
1069 CHAR16 NullCharacter;\r
1070 UINTN Index;\r
1071 UINT16 *NvRamMap;\r
1072 STRING_REF PopUp;\r
1073 EFI_INPUT_KEY Key;\r
1074 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
1075\r
1076 StringPtr = (CHAR16 *) L"\0";\r
1077 NullCharacter = CHAR_NULL;\r
1078\r
1079 FileFormTags = FileFormTagsHead;\r
1080\r
1081 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
1082 FileFormTags = FileFormTags->NextFile;\r
1083 }\r
1084\r
1085 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
1086 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1087\r
1088 Tag = MenuOption->ThisTag;\r
1089\r
1090 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
1091 NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];\r
1092\r
1093 //\r
1094 // If the op-code has a late check, ensure consistency checks are now applied\r
1095 //\r
1096 if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {\r
1097 if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {\r
1098 if (PopUp != 0x0000) {\r
1099 StringPtr = GetToken (PopUp, MenuOption->Handle);\r
1100\r
1101 CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);\r
1102\r
1103 do {\r
1104 WaitForKeyStroke (&Key);\r
1105\r
1106 switch (Key.UnicodeChar) {\r
1107\r
1108 case CHAR_CARRIAGE_RETURN:\r
1109 //\r
1110 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth\r
1111 //\r
1112 CopyMem (NvRamMap, &Tag->OldValue, Tag->StorageWidth);\r
1113 FreePool (StringPtr);\r
1114 break;\r
1115\r
1116 default:\r
1117 break;\r
1118 }\r
1119 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1120 }\r
1121\r
1122 return FALSE;\r
1123 }\r
1124 }\r
1125 }\r
1126\r
1127 return TRUE;\r
1128}\r
1129\r
1130UINT16\r
1131GetWidth (\r
1132 IN EFI_TAG *Tag,\r
1133 IN EFI_HII_HANDLE Handle\r
1134 )\r
1135/*++\r
1136\r
1137Routine Description:\r
1138 Get the supported width for a particular op-code\r
1139\r
1140Arguments:\r
1141 Tag - The Tag structure passed in.\r
1142 Handle - The handle in the HII database being used\r
1143\r
1144Returns:\r
1145 Returns the number of CHAR16 characters that is support.\r
1146\r
1147\r
1148--*/\r
1149{\r
1150 CHAR16 *String;\r
1151 UINTN Size;\r
1152\r
1153 Size = 0x00;\r
1154\r
1155 //\r
1156 // See if the second text parameter is really NULL\r
1157 //\r
1158 if ((Tag->Operand == EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) {\r
1159 String = GetToken (Tag->TextTwo, Handle);\r
1160 Size = StrLen (String);\r
1161 FreePool (String);\r
1162 }\r
1163\r
1164 if ((Tag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
1165 (Tag->Operand == EFI_IFR_REF_OP) ||\r
1166 (Tag->Operand == EFI_IFR_PASSWORD_OP) ||\r
1167 (Tag->Operand == EFI_IFR_STRING_OP) ||\r
1168 (Tag->Operand == EFI_IFR_INVENTORY_OP) ||\r
1169 //\r
1170 // Allow a wide display if text op-code and no secondary text op-code\r
1171 //\r
1172 ((Tag->Operand == EFI_IFR_TEXT_OP) && (Size == 0x0000))\r
1173 ) {\r
1174 return (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
1175 } else {\r
1176 return (UINT16) gPromptBlockWidth;\r
1177 }\r
1178}\r
1179\r
1180UINT16\r
1181GetLineByWidth (\r
1182 IN CHAR16 *InputString,\r
1183 IN UINT16 LineWidth,\r
1184 IN OUT UINTN *Index,\r
1185 OUT CHAR16 **OutputString\r
1186 )\r
1187/*++\r
1188\r
1189Routine Description:\r
1190 Will copy LineWidth amount of a string in the OutputString buffer and return the\r
1191 number of CHAR16 characters that were copied into the OutputString buffer.\r
1192\r
1193Arguments:\r
1194 InputString - String description for this option.\r
1195 LineWidth - Width of the desired string to extract in CHAR16 characters\r
1196 Index - Where in InputString to start the copy process\r
1197 OutputString - Buffer to copy the string into\r
1198\r
1199Returns:\r
1200 Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
1201\r
1202\r
1203--*/\r
1204{\r
1205 static BOOLEAN Finished;\r
1206 UINT16 Count;\r
1207 UINT16 Count2;\r
1208\r
1209 if (Finished) {\r
1210 Finished = FALSE;\r
1211 return (UINT16) 0;\r
1212 }\r
1213\r
1214 Count = LineWidth;\r
1215 Count2 = 0;\r
1216\r
1217 *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
1218\r
1219 //\r
1220 // Ensure we have got a valid buffer\r
1221 //\r
1222 if (*OutputString != NULL) {\r
1223\r
1224 //\r
1225 //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
1226 //To avoid displaying this empty line in screen, just skip the two CHARs here.\r
1227 //\r
1228 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
1229 *Index = *Index + 2;\r
1230 }\r
1231\r
1232 //\r
1233 // Fast-forward the string and see if there is a carriage-return in the string\r
1234 //\r
1235 for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
1236 ;\r
1237\r
1238 //\r
1239 // Copy the desired LineWidth of data to the output buffer.\r
1240 // Also make sure that we don't copy more than the string.\r
1241 // Also make sure that if there are linefeeds, we account for them.\r
1242 //\r
1243 if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
1244 (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
1245 ) {\r
1246 //\r
1247 // Convert to CHAR16 value and show that we are done with this operation\r
1248 //\r
1249 LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
1250 if (LineWidth != 0) {\r
1251 Finished = TRUE;\r
1252 }\r
1253 } else {\r
1254 if (Count2 == LineWidth) {\r
1255 //\r
1256 // Rewind the string from the maximum size until we see a space to break the line\r
1257 //\r
1258 for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
1259 ;\r
1260 if (LineWidth == 0) {\r
1261 LineWidth = Count;\r
1262 }\r
1263 } else {\r
1264 LineWidth = Count2;\r
1265 }\r
1266 }\r
1267\r
1268 CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
1269\r
1270 //\r
1271 // If currently pointing to a space, increment the index to the first non-space character\r
1272 //\r
1273 for (;\r
1274 (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
1275 (*Index)++\r
1276 )\r
1277 ;\r
1278 *Index = (UINT16) (*Index + LineWidth);\r
1279 return LineWidth;\r
1280 } else {\r
1281 return (UINT16) 0;\r
1282 }\r
1283}\r
1284\r
1285STATIC\r
1286VOID\r
1287UpdateOptionSkipLines (\r
1288 IN EFI_IFR_DATA_ARRAY *PageData,\r
1289 IN UI_MENU_OPTION *MenuOption,\r
1290 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
1291 IN CHAR16 **OptionalString,\r
1292 IN UINTN SkipValue\r
1293 )\r
1294{\r
1295 UINTN Index;\r
1296 UINT16 Width;\r
1297 UINTN Row;\r
1298 UINTN OriginalRow;\r
1299 CHAR16 *OutputString;\r
1300 CHAR16 *OptionString;\r
1301\r
1302 Row = 0;\r
1303 OptionString = *OptionalString;\r
1304 OutputString = NULL;\r
1305\r
1306 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1307\r
1308 if (OptionString != NULL) {\r
1309 Width = (UINT16) gOptionBlockWidth;\r
1310\r
1311 OriginalRow = Row;\r
1312\r
1313 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1314 //\r
1315 // If there is more string to process print on the next row and increment the Skip value\r
1316 //\r
1317 if (StrLen (&OptionString[Index])) {\r
1318 if (SkipValue == 0) {\r
1319 Row++;\r
1320 //\r
1321 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1322 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1323 // some testing to ensure we are keeping this in-sync.\r
1324 //\r
1325 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1326 //\r
1327 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1328 MenuOption->Skip++;\r
1329 }\r
1330 }\r
1331 }\r
1332\r
1333 FreePool (OutputString);\r
1334 if (SkipValue != 0) {\r
1335 SkipValue--;\r
1336 }\r
1337 }\r
1338\r
1339 Row = OriginalRow;\r
1340 }\r
1341\r
1342 *OptionalString = OptionString;\r
1343}\r
1344//\r
1345// Search table for UiDisplayMenu()\r
1346//\r
1347SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
1348 { SCAN_UP, UiUp },\r
1349 { SCAN_DOWN, UiDown },\r
1350 { SCAN_PAGE_UP, UiPageUp },\r
1351 { SCAN_PAGE_DOWN, UiPageDown},\r
1352 { SCAN_ESC, UiReset},\r
1353 { SCAN_F2, UiPrevious},\r
1354 { SCAN_LEFT, UiLeft },\r
1355 { SCAN_RIGHT, UiRight },\r
1356 { SCAN_F9, UiDefault},\r
1357 { SCAN_F10, UiSave }\r
1358};\r
1359\r
1360SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
1361 { UiNoOperation, CfUiNoOperation },\r
1362 { UiDefault, CfUiDefault },\r
1363 { UiSelect, CfUiSelect },\r
1364 { UiUp, CfUiUp},\r
1365 { UiDown, CfUiDown },\r
1366 { UiLeft, CfUiLeft },\r
1367 { UiRight, CfUiRight },\r
1368 { UiReset, CfUiReset },\r
1369 { UiSave, CfUiSave },\r
1370 { UiPrevious, CfUiPrevious },\r
1371 { UiPageUp, CfUiPageUp },\r
1372 { UiPageDown, CfUiPageDown }\r
1373};\r
1374\r
1375UI_MENU_OPTION *\r
1376UiDisplayMenu (\r
1377 IN BOOLEAN SubMenu,\r
1378 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
1379 OUT EFI_IFR_DATA_ARRAY *PageData\r
1380 )\r
1381/*++\r
1382\r
1383Routine Description:\r
1384 Display menu and wait for user to select one menu option, then return it.\r
1385 If AutoBoot is enabled, then if user doesn't select any option,\r
1386 after period of time, it will automatically return the first menu option.\r
1387\r
1388Arguments:\r
1389 SubMenu - Indicate is sub menu.\r
1390 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.\r
1391 PageData - A pointer to the EFI_IFR_DATA_ARRAY.\r
1392\r
1393Returns:\r
1394 Return the pointer of the menu which selected,\r
1395 otherwise return NULL.\r
1396\r
1397--*/\r
1398{\r
1399 INTN SkipValue;\r
1400 INTN Difference;\r
1401 INTN OldSkipValue;\r
1402 UINTN Row;\r
1403 UINTN Col;\r
1404 UINTN Temp;\r
1405 UINTN Temp2;\r
1406 UINTN TopRow;\r
1407 UINTN BottomRow;\r
1408 UINTN OriginalRow;\r
1409 UINTN Index;\r
1410 UINTN DataAndTimeLineNumberPad;\r
1411 UINT32 Count;\r
1412 INT16 OriginalTimeOut;\r
1413 UINT8 *Location;\r
1414 UINT16 Width;\r
1415 CHAR16 *StringPtr;\r
1416 CHAR16 *OptionString;\r
1417 CHAR16 *OutputString;\r
1418 CHAR16 *FormattedString;\r
1419 CHAR16 YesResponse;\r
1420 CHAR16 NoResponse;\r
1421 BOOLEAN NewLine;\r
1422 BOOLEAN Repaint;\r
1423 BOOLEAN SavedValue;\r
1424 EFI_STATUS Status;\r
1425 UI_MENU_LIST *UiMenuList;\r
1426 EFI_INPUT_KEY Key;\r
1427 LIST_ENTRY *Link;\r
1428 LIST_ENTRY *NewPos;\r
1429 LIST_ENTRY *TopOfScreen;\r
1430 LIST_ENTRY *SavedListEntry;\r
1431 UI_MENU_OPTION *Selection;\r
1432 UI_MENU_OPTION *MenuOption;\r
1433 UI_MENU_OPTION *NextMenuOption;\r
1434 UI_MENU_OPTION *SavedMenuOption;\r
1435 UI_MENU_OPTION *PreviousMenuOption;\r
1436 EFI_IFR_BINARY *IfrBinary;\r
1437 UI_CONTROL_FLAG ControlFlag;\r
1438 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
1439 EFI_FILE_FORM_TAGS *FileFormTags;\r
1440 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
1441 MENU_REFRESH_ENTRY *OldMenuRefreshEntry;\r
1442 UI_SCREEN_OPERATION ScreenOperation;\r
1443 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
1444 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;\r
1445 EFI_HII_VARIABLE_PACK_LIST *NvMapListHead;\r
1446 EFI_HII_VARIABLE_PACK_LIST *NvMapListNode;\r
1447 VOID *NvMap;\r
1448 UINTN NvMapSize;\r
1449\r
1450 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1451\r
1452 VariableDefinition = NULL;\r
1453 Status = EFI_SUCCESS;\r
1454 FormattedString = NULL;\r
1455 OptionString = NULL;\r
1456 ScreenOperation = UiNoOperation;\r
1457 NewLine = TRUE;\r
1458 FormCallback = NULL;\r
1459 FileFormTags = NULL;\r
1460 OutputString = NULL;\r
1461 gUpArrow = FALSE;\r
1462 gDownArrow = FALSE;\r
1463 SkipValue = 0;\r
1464 OldSkipValue = 0;\r
1465 MenuRefreshEntry = gMenuRefreshHead;\r
1466 OldMenuRefreshEntry = gMenuRefreshHead;\r
1467 NextMenuOption = NULL;\r
1468 PreviousMenuOption = NULL;\r
1469 SavedMenuOption = NULL;\r
1470 IfrBinary = NULL;\r
1471 NvMap = NULL;\r
1472 NvMapSize = 0;\r
1473\r
1474 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1475\r
1476 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
1477 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1478 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1479 } else {\r
1480 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1481 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1482 }\r
1483\r
1484 if (SubMenu) {\r
1485 Col = LocalScreen.LeftColumn;\r
1486 } else {\r
1487 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
1488 }\r
1489\r
1490 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1491\r
1492 TopOfScreen = Menu.ForwardLink;\r
1493 Repaint = TRUE;\r
1494 MenuOption = NULL;\r
1495\r
1496 //\r
1497 // Get user's selection\r
1498 //\r
1499 Selection = NULL;\r
1500 NewPos = Menu.ForwardLink;\r
1501 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1502\r
1503 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1504\r
1505 ControlFlag = CfInitialization;\r
1506\r
1507 while (TRUE) {\r
1508 switch (ControlFlag) {\r
1509 case CfInitialization:\r
1510 ControlFlag = CfCheckSelection;\r
1511 if (gExitRequired) {\r
1512 ScreenOperation = UiReset;\r
1513 ControlFlag = CfScreenOperation;\r
1514 } else if (gSaveRequired) {\r
1515 ScreenOperation = UiSave;\r
1516 ControlFlag = CfScreenOperation;\r
1517 } else if (IsListEmpty (&Menu)) {\r
1518 ControlFlag = CfReadKey;\r
1519 }\r
1520 break;\r
1521\r
1522 case CfCheckSelection:\r
1523 if (Selection != NULL) {\r
1524 ControlFlag = CfExit;\r
1525 } else {\r
1526 ControlFlag = CfRepaint;\r
1527 }\r
1528\r
1529 FileFormTags = FileFormTagsHead;\r
1530 break;\r
1531\r
1532 case CfRepaint:\r
1533 ControlFlag = CfRefreshHighLight;\r
1534\r
1535 if (Repaint) {\r
1536 //\r
1537 // Display menu\r
1538 //\r
1539 SavedMenuOption = MenuOption;\r
1540 gDownArrow = FALSE;\r
1541 gUpArrow = FALSE;\r
1542 Row = TopRow;\r
1543\r
1544 Temp = SkipValue;\r
1545 Temp2 = SkipValue;\r
1546\r
1547 ClearLines (\r
1548 LocalScreen.LeftColumn,\r
1549 LocalScreen.RightColumn,\r
1550 TopRow - SCROLL_ARROW_HEIGHT,\r
1551 BottomRow + SCROLL_ARROW_HEIGHT,\r
1552 FIELD_TEXT | FIELD_BACKGROUND\r
1553 );\r
1554\r
1555 while (gMenuRefreshHead != NULL) {\r
1556 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
1557\r
1558 FreePool (gMenuRefreshHead);\r
1559\r
1560 gMenuRefreshHead = OldMenuRefreshEntry;\r
1561 }\r
1562\r
1563 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
1564 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1565 MenuOption->Row = Row;\r
1566 OriginalRow = Row;\r
1567 MenuOption->Col = Col;\r
1568 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1569\r
1570 if (SubMenu) {\r
1571 if (MenuOption->ThisTag->GrayOut) {\r
1572 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1573 } else {\r
1574 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
1575 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1576 }\r
1577 }\r
1578\r
1579 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1580\r
1581 OriginalRow = Row;\r
1582\r
1583 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1584 if ((Temp == 0) && (Row <= BottomRow)) {\r
1585 PrintStringAt (Col, Row, OutputString);\r
1586 }\r
1587 //\r
1588 // If there is more string to process print on the next row and increment the Skip value\r
1589 //\r
1590 if (StrLen (&MenuOption->Description[Index])) {\r
1591 if (Temp == 0) {\r
1592 Row++;\r
1593 }\r
1594 }\r
1595\r
1596 FreePool (OutputString);\r
1597 if (Temp != 0) {\r
1598 Temp--;\r
1599 }\r
1600 }\r
1601\r
1602 Temp = 0;\r
1603\r
1604 Row = OriginalRow;\r
1605\r
1606 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1607 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1608\r
1609 if (OptionString != NULL) {\r
1610 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
1611 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
1612 ) {\r
1613 //\r
1614 // If leading spaces on OptionString - remove the spaces\r
1615 //\r
1616 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1617 MenuOption->OptCol++;\r
1618 }\r
1619\r
1620 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1621 OptionString[Count] = OptionString[Index];\r
1622 Count++;\r
1623 }\r
1624\r
1625 OptionString[Count] = CHAR_NULL;\r
1626 }\r
1627\r
1628 //\r
1629 // If this is a date or time op-code and is used to reflect an RTC, register the op-code\r
1630 //\r
1631 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
1632 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) &&\r
1633 (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {\r
1634\r
1635 if (gMenuRefreshHead == NULL) {\r
1636 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1637 ASSERT (MenuRefreshEntry != NULL);\r
1638 MenuRefreshEntry->MenuOption = MenuOption;\r
1639 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1640 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1641 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1642 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1643 gMenuRefreshHead = MenuRefreshEntry;\r
1644 } else {\r
1645 //\r
1646 // Advance to the last entry\r
1647 //\r
1648 for (MenuRefreshEntry = gMenuRefreshHead;\r
1649 MenuRefreshEntry->Next != NULL;\r
1650 MenuRefreshEntry = MenuRefreshEntry->Next\r
1651 )\r
1652 ;\r
1653 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1654 ASSERT (MenuRefreshEntry->Next != NULL);\r
1655 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1656 MenuRefreshEntry->MenuOption = MenuOption;\r
1657 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1658 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1659 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1660 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1661 }\r
1662 }\r
1663\r
1664 Width = (UINT16) gOptionBlockWidth;\r
1665\r
1666 OriginalRow = Row;\r
1667\r
1668 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1669 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1670 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1671 }\r
1672 //\r
1673 // If there is more string to process print on the next row and increment the Skip value\r
1674 //\r
1675 if (StrLen (&OptionString[Index])) {\r
1676 if (Temp2 == 0) {\r
1677 Row++;\r
1678 //\r
1679 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1680 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1681 // some testing to ensure we are keeping this in-sync.\r
1682 //\r
1683 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1684 //\r
1685 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1686 MenuOption->Skip++;\r
1687 }\r
1688 }\r
1689 }\r
1690\r
1691 FreePool (OutputString);\r
1692 if (Temp2 != 0) {\r
1693 Temp2--;\r
1694 }\r
1695 }\r
1696\r
1697 Temp2 = 0;\r
1698 Row = OriginalRow;\r
1699 }\r
1700 //\r
1701 // If this is a text op with secondary text information\r
1702 //\r
1703 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {\r
1704 StringPtr = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle);\r
1705\r
1706 Width = (UINT16) gOptionBlockWidth;\r
1707\r
1708 OriginalRow = Row;\r
1709\r
1710 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1711 if ((Temp == 0) && (Row <= BottomRow)) {\r
1712 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1713 }\r
1714 //\r
1715 // If there is more string to process print on the next row and increment the Skip value\r
1716 //\r
1717 if (StrLen (&StringPtr[Index])) {\r
1718 if (Temp2 == 0) {\r
1719 Row++;\r
1720 //\r
1721 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1722 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1723 // some testing to ensure we are keeping this in-sync.\r
1724 //\r
1725 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1726 //\r
1727 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1728 MenuOption->Skip++;\r
1729 }\r
1730 }\r
1731 }\r
1732\r
1733 FreePool (OutputString);\r
1734 if (Temp2 != 0) {\r
1735 Temp2--;\r
1736 }\r
1737 }\r
1738\r
1739 Row = OriginalRow;\r
1740 FreePool (StringPtr);\r
1741 }\r
1742 } else {\r
1743 //\r
1744 // For now, assume left-justified 72 width max setup entries\r
1745 //\r
1746 PrintStringAt (Col, Row, MenuOption->Description);\r
1747 }\r
1748 //\r
1749 // Tracker 6210 - need to handle the bottom of the display\r
1750 //\r
1751 if (MenuOption->Skip > 1) {\r
1752 Row += MenuOption->Skip - SkipValue;\r
1753 SkipValue = 0;\r
1754 } else {\r
1755 Row += MenuOption->Skip;\r
1756 }\r
1757\r
1758 if (Row > BottomRow) {\r
1759 if (!ValueIsScroll (FALSE, Link)) {\r
1760 gDownArrow = TRUE;\r
1761 }\r
1762\r
1763 Row = BottomRow + 1;\r
1764 break;\r
1765 }\r
1766 }\r
1767\r
1768 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
1769 gUpArrow = TRUE;\r
1770 }\r
1771\r
1772 if (gUpArrow) {\r
1773 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1774 PrintAt (\r
1775 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1776 TopRow - SCROLL_ARROW_HEIGHT,\r
1777 (CHAR16 *) L"%c",\r
1778 ARROW_UP\r
1779 );\r
1780 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1781 }\r
1782\r
1783 if (gDownArrow) {\r
1784 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1785 PrintAt (\r
1786 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1787 BottomRow + SCROLL_ARROW_HEIGHT,\r
1788 (CHAR16 *) L"%c",\r
1789 ARROW_DOWN\r
1790 );\r
1791 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1792 }\r
1793\r
1794 if (SavedMenuOption != NULL) {\r
1795 MenuOption = SavedMenuOption;\r
1796 }\r
1797 }\r
1798 break;\r
1799\r
1800 case CfRefreshHighLight:\r
1801 ControlFlag = CfUpdateHelpString;\r
1802 //\r
1803 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
1804 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
1805 //\r
1806 SavedValue = Repaint;\r
1807 Repaint = FALSE;\r
1808\r
1809 if (NewPos != NULL) {\r
1810 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1811 if (SubMenu) {\r
1812 if (gLastOpr && (gEntryNumber != -1)) {\r
1813 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1814 if (gEntryNumber != MenuOption->EntryNumber) {\r
1815 ScreenOperation = UiDown;\r
1816 ControlFlag = CfScreenOperation;\r
1817 break;\r
1818 } else {\r
1819 gLastOpr = FALSE;\r
1820 }\r
1821 }\r
1822\r
1823 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1824 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1825 if (OptionString != NULL) {\r
1826 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
1827 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
1828 ) {\r
1829 //\r
1830 // If leading spaces on OptionString - remove the spaces\r
1831 //\r
1832 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1833 ;\r
1834\r
1835 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1836 OptionString[Count] = OptionString[Index];\r
1837 Count++;\r
1838 }\r
1839\r
1840 OptionString[Count] = CHAR_NULL;\r
1841 }\r
1842\r
1843 Width = (UINT16) gOptionBlockWidth;\r
1844\r
1845 OriginalRow = MenuOption->Row;\r
1846\r
1847 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1848 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1849 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1850 }\r
1851 //\r
1852 // If there is more string to process print on the next row and increment the Skip value\r
1853 //\r
1854 if (StrLen (&OptionString[Index])) {\r
1855 MenuOption->Row++;\r
1856 }\r
1857\r
1858 FreePool (OutputString);\r
1859 }\r
1860\r
1861 MenuOption->Row = OriginalRow;\r
1862 } else {\r
1863 if (NewLine) {\r
1864 if (MenuOption->ThisTag->GrayOut) {\r
1865 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1866 } else {\r
1867 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
1868 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1869 }\r
1870 }\r
1871\r
1872 OriginalRow = MenuOption->Row;\r
1873 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1874\r
1875 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1876 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1877 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1878 }\r
1879 //\r
1880 // If there is more string to process print on the next row and increment the Skip value\r
1881 //\r
1882 if (StrLen (&MenuOption->Description[Index])) {\r
1883 MenuOption->Row++;\r
1884 }\r
1885\r
1886 FreePool (OutputString);\r
1887 }\r
1888\r
1889 MenuOption->Row = OriginalRow;\r
1890 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1891 }\r
1892 }\r
1893 } else {\r
1894 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1895 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
1896 }\r
1897\r
1898 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1899\r
1900 if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {\r
1901 ScreenOperation = UiDown;\r
1902 ControlFlag = CfScreenOperation;\r
1903 break;\r
1904 } else {\r
1905 gPriorMenuEntry = 0;\r
1906 }\r
1907 //\r
1908 // This is only possible if we entered this page and the first menu option is\r
1909 // a "non-menu" item. In that case, force it UiDown\r
1910 //\r
1911 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
1912 //\r
1913 // If we previously hit an UP command and we are still sitting on a text operation\r
1914 // we must continue going up\r
1915 //\r
1916 if (ScreenOperation == UiUp) {\r
1917 ControlFlag = CfScreenOperation;\r
1918 break;\r
1919 } else {\r
1920 ScreenOperation = UiDown;\r
1921 ControlFlag = CfScreenOperation;\r
1922 break;\r
1923 }\r
1924 }\r
1925 //\r
1926 // Set reverse attribute\r
1927 //\r
1928 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
1929 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1930\r
1931 //\r
1932 // Assuming that we have a refresh linked-list created, lets annotate the\r
1933 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
1934 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
1935 //\r
1936 if (gMenuRefreshHead != NULL) {\r
1937 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
1938 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1939 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
1940 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
1941 }\r
1942 }\r
1943 }\r
1944\r
1945 if (SubMenu) {\r
1946 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1947 if (OptionString != NULL) {\r
1948 if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
1949 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
1950 ) {\r
1951 //\r
1952 // If leading spaces on OptionString - remove the spaces\r
1953 //\r
1954 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1955 ;\r
1956\r
1957 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1958 OptionString[Count] = OptionString[Index];\r
1959 Count++;\r
1960 }\r
1961\r
1962 OptionString[Count] = CHAR_NULL;\r
1963 }\r
1964 Width = (UINT16) gOptionBlockWidth;\r
1965\r
1966 OriginalRow = MenuOption->Row;\r
1967\r
1968 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1969 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1970 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1971 }\r
1972 //\r
1973 // If there is more string to process print on the next row and increment the Skip value\r
1974 //\r
1975 if (StrLen (&OptionString[Index])) {\r
1976 MenuOption->Row++;\r
1977 }\r
1978\r
1979 FreePool (OutputString);\r
1980 }\r
1981\r
1982 MenuOption->Row = OriginalRow;\r
1983 } else {\r
1984 if (NewLine) {\r
1985 OriginalRow = MenuOption->Row;\r
1986\r
1987 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1988\r
1989 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1990 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1991 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1992 }\r
1993 //\r
1994 // If there is more string to process print on the next row and increment the Skip value\r
1995 //\r
1996 if (StrLen (&MenuOption->Description[Index])) {\r
1997 MenuOption->Row++;\r
1998 }\r
1999\r
2000 FreePool (OutputString);\r
2001 }\r
2002\r
2003 MenuOption->Row = OriginalRow;\r
2004\r
2005 }\r
2006 }\r
2007\r
2008 if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||\r
2009 ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||\r
2010 (ScreenOperation == UiNoOperation)\r
2011 ) {\r
2012 UpdateKeyHelp (MenuOption, FALSE);\r
2013 }\r
2014 } else {\r
2015 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2016 }\r
2017 //\r
2018 // Clear reverse attribute\r
2019 //\r
2020 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2021 }\r
2022 //\r
2023 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2024 // if we didn't break halfway when process CfRefreshHighLight.\r
2025 //\r
2026 Repaint = SavedValue;\r
2027 break;\r
2028\r
2029 case CfUpdateHelpString:\r
2030 ControlFlag = CfPrepareToReadKey;\r
2031\r
2032 if (SubMenu &&\r
2033 (Repaint || NewLine ||\r
2034 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2035 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) &&\r
2036 !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
2037 //\r
2038 // Don't print anything if it is a NULL help token\r
2039 //\r
2040 if (MenuOption->ThisTag->Help == 0x00000000) {\r
2041 StringPtr = (CHAR16 *) L"\0";\r
2042 } else {\r
2043 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2044 }\r
2045\r
2046 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2047\r
2048 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2049\r
2050 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2051 //\r
2052 // Pad String with spaces to simulate a clearing of the previous line\r
2053 //\r
2054 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
2055 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], (CHAR16 *) L" ");\r
2056 }\r
2057\r
2058 PrintStringAt (\r
2059 LocalScreen.RightColumn - gHelpBlockWidth,\r
2060 Index + TopRow,\r
2061 &FormattedString[Index * gHelpBlockWidth * 2]\r
2062 );\r
2063 }\r
2064 }\r
2065 //\r
2066 // Reset this flag every time we finish using it.\r
2067 //\r
2068 Repaint = FALSE;\r
2069 NewLine = FALSE;\r
2070 break;\r
2071\r
2072 case CfPrepareToReadKey:\r
2073 ControlFlag = CfReadKey;\r
2074\r
2075 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
2076 FileFormTags = FileFormTags->NextFile;\r
2077 }\r
2078\r
2079 ScreenOperation = UiNoOperation;\r
2080\r
2081 Status = gBS->HandleProtocol (\r
2082 (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,\r
2083 &gEfiFormCallbackProtocolGuid,\r
2084 (VOID **) &FormCallback\r
2085 );\r
2086\r
2087 break;\r
2088\r
2089 case CfReadKey:\r
2090 ControlFlag = CfScreenOperation;\r
2091\r
2092 OriginalTimeOut = FrontPageTimeOutValue;\r
2093 do {\r
2094 if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {\r
2095 //\r
2096 // Remember that if set to 0, must immediately boot an option\r
2097 //\r
2098 if (FrontPageTimeOutValue == 0) {\r
2099 FrontPageTimeOutValue = 0xFFFF;\r
2100 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2101 if (EFI_ERROR (Status)) {\r
2102 Status = EFI_TIMEOUT;\r
2103 }\r
2104 break;\r
2105 }\r
2106\r
2107 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);\r
2108 if (Status == EFI_TIMEOUT) {\r
2109 EFI_IFR_DATA_ENTRY *DataEntry;\r
2110\r
2111 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
2112\r
2113 PageData->EntryCount = 1;\r
2114 Count = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);\r
2115 CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));\r
2116\r
2117 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2118 FormCallback->Callback (\r
2119 FormCallback,\r
2120 0xFFFF,\r
2121 (EFI_IFR_DATA_ARRAY *) PageData,\r
2122 NULL\r
2123 );\r
2124 }\r
2125 //\r
2126 // Count down 1 second\r
2127 //\r
2128 FrontPageTimeOutValue--;\r
2129\r
2130 } else {\r
2131 ASSERT (!EFI_ERROR (Status));\r
2132 PageData->EntryCount = 0;\r
2133 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2134 FormCallback->Callback (\r
2135 FormCallback,\r
2136 0xFFFE,\r
2137 (EFI_IFR_DATA_ARRAY *) PageData,\r
2138 NULL\r
2139 );\r
2140 }\r
2141\r
2142 FrontPageTimeOutValue = 0xFFFF;\r
2143 }\r
2144 } else {\r
2145 //\r
2146 // Wait for user's selection, no auto boot\r
2147 //\r
2148 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
2149 }\r
2150 } while (Status == EFI_TIMEOUT);\r
2151\r
2152 if (gFirstIn) {\r
2153 gFirstIn = FALSE;\r
2154 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2155 DisableQuietBoot ();\r
2156 }\r
2157\r
2158 if (Status == EFI_TIMEOUT) {\r
2159 Key.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
2160 } else {\r
2161 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2162 //\r
2163 // if we encounter error, continue to read another key in.\r
2164 //\r
2165 if (EFI_ERROR (Status)) {\r
2166 ControlFlag = CfReadKey;\r
2167 continue;\r
2168 }\r
2169 }\r
2170\r
2171 switch (Key.UnicodeChar) {\r
2172 case CHAR_CARRIAGE_RETURN:\r
2173 Selection = MenuOption;\r
2174 ScreenOperation = UiSelect;\r
2175 gDirection = 0;\r
2176 break;\r
2177\r
2178 //\r
2179 // We will push the adjustment of these numeric values directly to the input handler\r
2180 //\r
2181 case '+':\r
2182 case '-':\r
2183 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2184\r
2185 if (Key.UnicodeChar == '+') {\r
2186 gDirection = SCAN_RIGHT;\r
2187 } else {\r
2188 gDirection = SCAN_LEFT;\r
2189 }\r
2190\r
2191 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);\r
2192 }\r
2193 break;\r
2194\r
2195 case '^':\r
2196 ScreenOperation = UiUp;\r
2197 break;\r
2198\r
2199 case 'V':\r
2200 case 'v':\r
2201 ScreenOperation = UiDown;\r
2202 break;\r
2203\r
2204 case ' ':\r
2205 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
2206 if (SubMenu) {\r
2207 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {\r
2208 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2209 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2210 Selection = MenuOption;\r
2211 ScreenOperation = UiSelect;\r
2212 }\r
2213 }\r
2214 }\r
2215 break;\r
2216\r
2217 case CHAR_NULL:\r
2218 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
2219 ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
2220 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
2221 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2222 ) {\r
2223 //\r
2224 // If the function key has been disabled, just ignore the key.\r
2225 //\r
2226 } else {\r
2227 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2228 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2229 if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) {\r
2230 if (SubMenu) {\r
2231 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2232 }\r
2233 } else {\r
2234 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2235 }\r
2236 }\r
2237 }\r
2238 }\r
2239 break;\r
2240 }\r
2241 break;\r
2242\r
2243 case CfScreenOperation:\r
2244 IfrBinary = gBinaryDataHead;\r
2245\r
2246 //\r
2247 // Advance to the Ifr we are using\r
2248 //\r
2249 for (Index = 0; Index < gActiveIfr; Index++) {\r
2250 IfrBinary = IfrBinary->Next;\r
2251 }\r
2252\r
2253 if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
2254 //\r
2255 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
2256 // ignore the selection and go back to reading keys.\r
2257 //\r
2258 if (IsListEmpty (&Menu)) {\r
2259 ControlFlag = CfReadKey;\r
2260 break;\r
2261 }\r
2262 //\r
2263 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2264 //\r
2265 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
2266 NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2267 if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) {\r
2268 break;\r
2269 }\r
2270 }\r
2271\r
2272 if (Link == &Menu) {\r
2273 ControlFlag = CfPrepareToReadKey;\r
2274 break;\r
2275 }\r
2276 }\r
2277\r
2278 for (Index = 0;\r
2279 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2280 Index++\r
2281 ) {\r
2282 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2283 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2284 }\r
2285 }\r
2286\r
2287 break;\r
2288\r
2289 case CfUiPrevious:\r
2290 ControlFlag = CfCheckSelection;\r
2291 //\r
2292 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2293 //\r
2294 if (MenuOption != NULL) {\r
2295 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2296 Selection = NULL;\r
2297 Repaint = TRUE;\r
2298 break;\r
2299 }\r
2300 }\r
2301\r
2302 if (IsListEmpty (&gMenuList)) {\r
2303 Selection = NULL;\r
2304 if (IsListEmpty (&Menu)) {\r
2305 ControlFlag = CfReadKey;\r
2306 }\r
2307 break;\r
2308 }\r
2309\r
2310 gLastOpr = TRUE;\r
2311\r
2312 while (gMenuRefreshHead != NULL) {\r
2313 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
2314\r
2315 FreePool (gMenuRefreshHead);\r
2316\r
2317 gMenuRefreshHead = OldMenuRefreshEntry;\r
2318 }\r
2319 //\r
2320 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag\r
2321 //\r
2322 if (SubMenu) {\r
2323 UiRemoveMenuListEntry (MenuOption, &Selection);\r
2324 Selection->Previous = TRUE;\r
2325 UiFreeMenu ();\r
2326 UiInitMenu ();\r
2327 }\r
2328\r
2329 gActiveIfr = Selection->IfrNumber;\r
2330 return Selection;\r
2331\r
2332 case CfUiSelect:\r
2333 ControlFlag = CfCheckSelection;\r
2334\r
2335 ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);\r
2336\r
2337 if (SubMenu) {\r
2338 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP &&\r
2339 !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) ||\r
2340 (MenuOption->ThisTag->GrayOut) ||\r
2341 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2342 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2343 Selection = NULL;\r
2344 break;\r
2345 }\r
2346\r
2347 NewLine = TRUE;\r
2348 UpdateKeyHelp (MenuOption, TRUE);\r
2349 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);\r
2350\r
2351 if (EFI_ERROR (Status)) {\r
2352 Selection = NULL;\r
2353 Repaint = TRUE;\r
2354 break;\r
2355 }\r
2356\r
2357 if (OptionString != NULL) {\r
2358 PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);\r
2359 }\r
2360\r
2361 if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
2362 Selection = MenuOption;\r
2363 }\r
2364\r
2365 if (Selection == NULL) {\r
2366 break;\r
2367 }\r
2368\r
2369 Location = (UINT8 *) &PageData->EntryCount;\r
2370\r
2371 //\r
2372 // If not a goto, dump single piece of data, otherwise dump everything\r
2373 //\r
2374 if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) {\r
2375 //\r
2376 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2377 //\r
2378 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2379 Selection = NULL;\r
2380 Repaint = TRUE;\r
2381 break;\r
2382 }\r
2383\r
2384 UiAddMenuListEntry (Selection);\r
2385 gPriorMenuEntry = 0;\r
2386\r
2387 //\r
2388 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious\r
2389 //\r
2390 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
2391 UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;\r
2392\r
2393 gLastOpr = FALSE;\r
2394\r
2395 //\r
2396 // Rewind to the beginning of the menu\r
2397 //\r
2398 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2399 ;\r
2400\r
2401 //\r
2402 // Get Total Count of Menu entries\r
2403 //\r
2404 for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {\r
2405 Count++;\r
2406 }\r
2407 //\r
2408 // Rewind to the beginning of the menu\r
2409 //\r
2410 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2411 ;\r
2412\r
2413 //\r
2414 // Copy the number of entries being described to the PageData location\r
2415 //\r
2416 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2417\r
2418 for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {\r
2419\r
2420 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2421 Location[Index] = MenuOption->ThisTag->Operand;\r
2422 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2423 CopyMem (\r
2424 &Location[Index + 4],\r
2425 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2426 MenuOption->ThisTag->StorageWidth\r
2427 );\r
2428 NewPos = NewPos->ForwardLink;\r
2429 }\r
2430 } else {\r
2431\r
2432 gPriorMenuEntry = MenuOption->EntryNumber;\r
2433\r
2434 Count = 1;\r
2435\r
2436 //\r
2437 // Copy the number of entries being described to the PageData location\r
2438 //\r
2439 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2440\r
2441 //\r
2442 // Start at PageData[4] since the EntryCount is a UINT32\r
2443 //\r
2444 Index = 4;\r
2445\r
2446 //\r
2447 // Copy data to destination\r
2448 //\r
2449 Location[Index] = MenuOption->ThisTag->Operand;\r
2450 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2451 CopyMem (\r
2452 &Location[Index + 4],\r
2453 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2454 MenuOption->ThisTag->StorageWidth\r
2455 );\r
2456 }\r
2457 }\r
2458 break;\r
2459\r
2460 case CfUiReset:\r
2461 ControlFlag = CfCheckSelection;\r
2462 gLastOpr = FALSE;\r
2463 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
2464 break;\r
2465 }\r
2466 //\r
2467 // If NV flag is up, prompt user\r
2468 //\r
2469 if (gNvUpdateRequired) {\r
2470 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2471\r
2472 YesResponse = gYesResponse[0];\r
2473 NoResponse = gNoResponse[0];\r
2474\r
2475 do {\r
2476 CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
2477 } while\r
2478 (\r
2479 (Key.ScanCode != SCAN_ESC) &&\r
2480 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
2481 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
2482 );\r
2483\r
2484 //\r
2485 // If the user hits the YesResponse key\r
2486 //\r
2487 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
2488 } else {\r
2489 Repaint = TRUE;\r
2490 NewLine = TRUE;\r
2491 break;\r
2492 }\r
2493 }\r
2494 //\r
2495 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2496 //\r
2497 if (MenuOption != NULL) {\r
2498 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2499 Selection = NULL;\r
2500 Repaint = TRUE;\r
2501 NewLine = TRUE;\r
2502 break;\r
2503 }\r
2504 }\r
2505\r
2506 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2507 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
2508\r
2509 if (SubMenu) {\r
2510 UiFreeMenuList ();\r
2511 gST->ConOut->ClearScreen (gST->ConOut);\r
2512 return NULL;\r
2513 }\r
2514\r
2515 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2516 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2517\r
2518 if (IfrBinary->UnRegisterOnExit) {\r
2519 Hii->RemovePack (Hii, MenuOption->Handle);\r
2520 }\r
2521\r
2522 UiFreeMenu ();\r
2523\r
2524 //\r
2525 // Clean up the allocated data buffers\r
2526 //\r
2527 FreeData (FileFormTagsHead, FormattedString, OptionString);\r
2528\r
2529 gST->ConOut->ClearScreen (gST->ConOut);\r
2530 return NULL;\r
2531\r
2532 case CfUiLeft:\r
2533 ControlFlag = CfCheckSelection;\r
2534 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2535 if (MenuOption->Skip == 1) {\r
2536 //\r
2537 // In the tail of the Date/Time op-code set, go left.\r
2538 //\r
2539 NewPos = NewPos->BackLink;\r
2540 } else {\r
2541 //\r
2542 // In the middle of the Data/Time op-code set, go left.\r
2543 //\r
2544 NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2545 if (NextMenuOption->Skip == 1) {\r
2546 NewPos = NewPos->BackLink;\r
2547 }\r
2548 }\r
2549 }\r
2550 break;\r
2551\r
2552 case CfUiRight:\r
2553 ControlFlag = CfCheckSelection;\r
2554 if ((MenuOption->Skip == 0) &&\r
2555 ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP))\r
2556 ) {\r
2557 //\r
2558 // We are in the head or middle of the Date/Time op-code set, advance right.\r
2559 //\r
2560 NewPos = NewPos->ForwardLink;\r
2561 }\r
2562 break;\r
2563\r
2564 case CfUiUp:\r
2565 ControlFlag = CfCheckSelection;\r
2566\r
2567 if (NewPos->BackLink != &Menu) {\r
2568 NewLine = TRUE;\r
2569 //\r
2570 // Adjust Date/Time position before we advance forward.\r
2571 //\r
2572 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2573\r
2574 //\r
2575 // Caution that we have already rewind to the top, don't go backward in this situation.\r
2576 //\r
2577 if (NewPos->BackLink != &Menu) {\r
2578 NewPos = NewPos->BackLink;\r
2579 }\r
2580\r
2581 PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2582\r
2583 //\r
2584 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
2585 // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
2586 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2587 // checking can be done.\r
2588 //\r
2589 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);\r
2590\r
2591 if (SubMenu) {\r
2592 //\r
2593 // If the previous MenuOption contains a display-only op-code, skip to the next one\r
2594 //\r
2595 if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {\r
2596 //\r
2597 // This is ok as long as not at the end of the list\r
2598 //\r
2599 if (NewPos->BackLink == &Menu) {\r
2600 //\r
2601 // If we are at the start of the list, then this list must start with a display only\r
2602 // piece of data, so do not allow the backward motion\r
2603 //\r
2604 ScreenOperation = UiDown;\r
2605\r
2606 if (PreviousMenuOption->Row <= TopRow) {\r
2607 if (TopOfScreen->BackLink != &Menu) {\r
2608 TopOfScreen = TopOfScreen->BackLink;\r
2609 Repaint = TRUE;\r
2610 }\r
2611 }\r
2612\r
2613 UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);\r
2614 break;\r
2615 }\r
2616 }\r
2617 }\r
2618 //\r
2619 // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
2620 // don't worry about a redraw.\r
2621 //\r
2622 if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||\r
2623 (PreviousMenuOption->Skip > MenuOption->Row)\r
2624 ) {\r
2625 do {\r
2626 if (TopOfScreen->BackLink == &Menu) {\r
2627 break;\r
2628 }\r
2629\r
2630 Repaint = TRUE;\r
2631\r
2632 //\r
2633 // Is the current top of screen a zero-advance op-code?\r
2634 // If so, keep moving forward till we hit a >0 advance op-code\r
2635 //\r
2636 SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2637 TopOfScreen = TopOfScreen->BackLink;\r
2638 } while (SavedMenuOption->Skip == 0);\r
2639 //\r
2640 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2641 //\r
2642 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2643 }\r
2644\r
2645 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2646 } else {\r
2647 if (SubMenu) {\r
2648 SavedMenuOption = MenuOption;\r
2649 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2650 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
2651 //\r
2652 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2653 //\r
2654 ScreenOperation = UiDown;\r
2655 ControlFlag = CfScreenOperation;\r
2656 break;\r
2657 }\r
2658\r
2659 MenuOption = SavedMenuOption;\r
2660 }\r
2661 }\r
2662 break;\r
2663\r
2664 case CfUiPageUp:\r
2665 ControlFlag = CfCheckSelection;\r
2666\r
2667 SavedListEntry = NewPos;\r
2668 Link = TopOfScreen;\r
2669 for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {\r
2670 if (Link->BackLink == &Menu) {\r
2671 TopOfScreen = Link;\r
2672 Link = SavedListEntry;\r
2673 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2674 break;\r
2675 }\r
2676\r
2677 NewLine = TRUE;\r
2678 Repaint = TRUE;\r
2679 Link = Link->BackLink;\r
2680 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2681 TopOfScreen = Link;\r
2682 SavedListEntry = Link;\r
2683 }\r
2684\r
2685 NewPos = Link;\r
2686\r
2687 //\r
2688 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2689 // Don't do this when we are already in the first page.\r
2690 //\r
2691 if (Repaint) {\r
2692 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2693 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2694 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2695 }\r
2696 break;\r
2697\r
2698 case CfUiPageDown:\r
2699 ControlFlag = CfCheckSelection;\r
2700\r
2701 SavedListEntry = NewPos;\r
2702 Link = TopOfScreen;\r
2703 NewPos = TopOfScreen;\r
2704 for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {\r
2705 if (NewPos->ForwardLink == &Menu) {\r
2706 NewPos = SavedListEntry;\r
2707 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2708 Link = TopOfScreen;\r
2709 NewLine = FALSE;\r
2710 Repaint = FALSE;\r
2711 break;\r
2712 }\r
2713\r
2714 NewLine = TRUE;\r
2715 Repaint = TRUE;\r
2716 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2717 NewPos = NewPos->ForwardLink;\r
2718 Link = NewPos;\r
2719 }\r
2720\r
2721 TopOfScreen = Link;\r
2722\r
2723 //\r
2724 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2725 // Don't do this when we are already in the last page.\r
2726 //\r
2727 if (Repaint) {\r
2728 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2729 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2730 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2731 }\r
2732 break;\r
2733\r
2734 case CfUiDown:\r
2735 ControlFlag = CfCheckSelection;\r
2736 //\r
2737 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
2738 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
2739 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2740 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
2741 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
2742 // the Date/Time op-code.\r
2743 //\r
2744 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);\r
2745\r
2746 if (NewPos->ForwardLink != &Menu) {\r
2747 NewLine = TRUE;\r
2748 NewPos = NewPos->ForwardLink;\r
2749 NextMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2750\r
2751 if (SubMenu) {\r
2752 //\r
2753 // If the next MenuOption contains a display-only op-code, skip to the next one\r
2754 // Also if the next MenuOption is date or time,\r
2755 //\r
2756 if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {\r
2757 //\r
2758 // This is ok as long as not at the end of the list\r
2759 //\r
2760 if (NewPos == &Menu) {\r
2761 //\r
2762 // If we are at the end of the list, then this list must end with a display only\r
2763 // piece of data, so do not allow the forward motion\r
2764 //\r
2765 UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);\r
2766 NewPos = NewPos->BackLink;\r
2767 ScreenOperation = UiUp;\r
2768 break;\r
2769 }\r
2770 }\r
2771 }\r
2772 //\r
2773 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
2774 //\r
2775 UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);\r
2776\r
2777 if (NextMenuOption->Skip > 1) {\r
2778 Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;\r
2779 } else {\r
2780 Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;\r
2781 }\r
2782 //\r
2783 // If we are going to scroll\r
2784 //\r
2785 if (Temp > BottomRow) {\r
2786 do {\r
2787 //\r
2788 // Is the current top of screen a zero-advance op-code?\r
2789 // If so, keep moving forward till we hit a >0 advance op-code\r
2790 //\r
2791 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2792\r
2793 //\r
2794 // If bottom op-code is more than one line or top op-code is more than one line\r
2795 //\r
2796 if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) {\r
2797 //\r
2798 // Is the bottom op-code greater than or equal in size to the top op-code?\r
2799 //\r
2800 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
2801 //\r
2802 // Skip the top op-code\r
2803 //\r
2804 TopOfScreen = TopOfScreen->ForwardLink;\r
2805 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
2806\r
2807 OldSkipValue = Difference;\r
2808\r
2809 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2810\r
2811 //\r
2812 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
2813 //\r
2814 for (;\r
2815 Difference >= (INTN) SavedMenuOption->Skip;\r
2816 Difference = Difference - (INTN) SavedMenuOption->Skip\r
2817 ) {\r
2818 //\r
2819 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
2820 //\r
2821 TopOfScreen = TopOfScreen->ForwardLink;\r
2822 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2823 if (Difference < (INTN) SavedMenuOption->Skip) {\r
2824 Difference = SavedMenuOption->Skip - Difference - 1;\r
2825 break;\r
2826 } else {\r
2827 if (Difference == (INTN) SavedMenuOption->Skip) {\r
2828 TopOfScreen = TopOfScreen->ForwardLink;\r
2829 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2830 Difference = SavedMenuOption->Skip - Difference;\r
2831 break;\r
2832 }\r
2833 }\r
2834 }\r
2835 //\r
2836 // Since we will act on this op-code in the next routine, and increment the\r
2837 // SkipValue, set the skips to one less than what is required.\r
2838 //\r
2839 SkipValue = Difference - 1;\r
2840\r
2841 } else {\r
2842 //\r
2843 // Since we will act on this op-code in the next routine, and increment the\r
2844 // SkipValue, set the skips to one less than what is required.\r
2845 //\r
2846 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
2847 }\r
2848 } else {\r
2849 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
2850 TopOfScreen = TopOfScreen->ForwardLink;\r
2851 break;\r
2852 } else {\r
2853 SkipValue = OldSkipValue;\r
2854 }\r
2855 }\r
2856 //\r
2857 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
2858 // Let's set a skip flag to smoothly scroll the top of the screen.\r
2859 //\r
2860 if (SavedMenuOption->Skip > 1) {\r
2861 if (SavedMenuOption == NextMenuOption) {\r
2862 SkipValue = 0;\r
2863 } else {\r
2864 SkipValue++;\r
2865 }\r
2866 } else {\r
2867 SkipValue = 0;\r
2868 TopOfScreen = TopOfScreen->ForwardLink;\r
2869 }\r
2870 } while (SavedMenuOption->Skip == 0);\r
2871\r
2872 Repaint = TRUE;\r
2873 OldSkipValue = SkipValue;\r
2874 }\r
2875\r
2876 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2877\r
2878 } else {\r
2879 if (SubMenu) {\r
2880 SavedMenuOption = MenuOption;\r
2881 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2882 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
2883 //\r
2884 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2885 //\r
2886 ScreenOperation = UiUp;\r
2887 ControlFlag = CfScreenOperation;\r
2888 break;\r
2889 }\r
2890\r
2891 MenuOption = SavedMenuOption;\r
2892 //\r
2893 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
2894 //\r
2895 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2896 }\r
2897 }\r
2898 break;\r
2899\r
2900 case CfUiSave:\r
2901 ControlFlag = CfCheckSelection;\r
2902 //\r
2903 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2904 //\r
2905 if (MenuOption != NULL) {\r
2906 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2907 Selection = NULL;\r
2908 Repaint = TRUE;\r
2909 break;\r
2910 }\r
2911 }\r
2912 //\r
2913 // If callbacks are active, and the callback has a Write method, try to use it\r
2914 //\r
2915 if (FileFormTags->VariableDefinitions->VariableName == NULL) {\r
2916 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2917 Status = FormCallback->NvWrite (\r
2918 FormCallback,\r
2919 (CHAR16 *) L"Setup",\r
2920 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2921 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2922 VariableDefinition->VariableSize,\r
2923 (VOID *) VariableDefinition->NvRamMap,\r
2924 &gResetRequired\r
2925 );\r
2926\r
2927 } else {\r
2928 Status = gRT->SetVariable (\r
2929 (CHAR16 *) L"Setup",\r
2930 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2931 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2932 VariableDefinition->VariableSize,\r
2933 (VOID *) VariableDefinition->NvRamMap\r
2934 );\r
2935 }\r
2936 } else {\r
2937 VariableDefinition = FileFormTags->VariableDefinitions;\r
2938\r
2939 for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {\r
2940 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2941 Status = FormCallback->NvWrite (\r
2942 FormCallback,\r
2943 VariableDefinition->VariableName,\r
2944 &VariableDefinition->Guid,\r
2945 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2946 VariableDefinition->VariableSize,\r
2947 (VOID *) VariableDefinition->NvRamMap,\r
2948 &gResetRequired\r
2949 );\r
2950\r
2951 } else {\r
2952 Status = gRT->SetVariable (\r
2953 VariableDefinition->VariableName,\r
2954 &VariableDefinition->Guid,\r
2955 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2956 VariableDefinition->VariableSize,\r
2957 (VOID *) VariableDefinition->NvRamMap\r
2958 );\r
2959 }\r
2960 }\r
2961 }\r
2962\r
2963 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2964 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2965 break;\r
2966\r
2967 case CfUiDefault:\r
2968 ControlFlag = CfCheckSelection;\r
2969\r
2970 NvMapListHead = NULL;\r
2971\r
2972 Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead);\r
2973\r
2974 if (!EFI_ERROR (Status)) {\r
2975 ASSERT_EFI_ERROR (NULL != NvMapListHead);\r
2976\r
2977 NvMapListNode = NvMapListHead;\r
2978\r
2979 while (NULL != NvMapListNode) {\r
2980 if (FileFormTags->VariableDefinitions->VariableId == NvMapListNode->VariablePack->VariableId) {\r
2981 NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);\r
2982 NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;\r
2983 break;\r
2984 }\r
2985 NvMapListNode = NvMapListNode->NextVariablePack;\r
2986 }\r
2987\r
2988 //\r
2989 // Free the buffer that was allocated.\r
2990 //\r
2991 FreePool (FileFormTags->VariableDefinitions->NvRamMap);\r
2992 FreePool (FileFormTags->VariableDefinitions->FakeNvRamMap);\r
2993\r
2994 //\r
2995 // Allocate, copy the NvRamMap.\r
2996 //\r
2997 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize - FileFormTags->VariableDefinitions->VariableSize);\r
2998 FileFormTags->VariableDefinitions->VariableSize = (UINT16) NvMapSize;\r
2999 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize + FileFormTags->VariableDefinitions->VariableSize);\r
3000\r
3001 FileFormTags->VariableDefinitions->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);\r
3002 ASSERT (FileFormTags->VariableDefinitions->NvRamMap != NULL);\r
3003\r
3004 FileFormTags->VariableDefinitions->FakeNvRamMap = AllocateZeroPool (NvMapSize + FileFormTags->VariableDefinitions->VariableFakeSize);\r
3005 ASSERT (FileFormTags->VariableDefinitions->FakeNvRamMap != NULL);\r
3006\r
3007 CopyMem (FileFormTags->VariableDefinitions->NvRamMap, NvMap, NvMapSize);\r
3008 FreePool (NvMapListHead);\r
3009 }\r
3010\r
3011 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);\r
3012 Repaint = TRUE;\r
3013 //\r
3014 // After the repaint operation, we should refresh the highlight.\r
3015 //\r
3016 NewLine = TRUE;\r
3017 break;\r
3018\r
3019 case CfUiNoOperation:\r
3020 ControlFlag = CfCheckSelection;\r
3021 break;\r
3022\r
3023 case CfExit:\r
3024 while (gMenuRefreshHead != NULL) {\r
3025 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
3026\r
3027 FreePool (gMenuRefreshHead);\r
3028\r
3029 gMenuRefreshHead = OldMenuRefreshEntry;\r
3030 }\r
3031\r
3032 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3033 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3034 gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");\r
3035\r
3036 gActiveIfr = MenuOption->IfrNumber;\r
3037 return Selection;\r
3038\r
3039 default:\r
3040 break;\r
3041 }\r
3042 }\r
3043}\r
3044\r
3045BOOLEAN\r
3046ValueIsScroll (\r
3047 IN BOOLEAN Direction,\r
3048 IN LIST_ENTRY *CurrentPos\r
3049 )\r
3050/*++\r
3051\r
3052Routine Description:\r
3053 Determine if the menu is the last menu that can be selected.\r
3054\r
3055Arguments:\r
3056 Direction - the scroll direction. False is down. True is up.\r
3057\r
3058Returns:\r
3059 FALSE -- the menu isn't the last menu that can be selected.\r
3060 TRUE -- the menu is the last menu that can be selected.\r
3061--*/\r
3062{\r
3063 LIST_ENTRY *Temp;\r
3064 UI_MENU_OPTION *MenuOption;\r
3065 MenuOption = NULL;\r
3066\r
3067 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
3068\r
3069 if (Temp == &Menu) {\r
3070 return TRUE;\r
3071 }\r
3072\r
3073 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
3074 MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3075 if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {\r
3076 return FALSE;\r
3077 }\r
3078 }\r
3079\r
3080 return TRUE;\r
3081}\r
3082\r
3083UINTN\r
3084AdjustDateAndTimePosition (\r
3085 IN BOOLEAN DirectionUp,\r
3086 IN LIST_ENTRY **CurrentPosition\r
3087 )\r
3088/*++\r
3089Routine Description:\r
3090 Adjust Data and Time tag position accordingly.\r
3091 Data format : [01/02/2004] [11:22:33]\r
3092 Line number : 0 0 1 0 0 1\r
3093\r
3094Arguments:\r
3095 Direction - the up or down direction. False is down. True is up.\r
3096 CurrentPos - Current position.\r
3097\r
3098Returns:\r
3099 Return line number to pad. It is possible that we stand on a zero-advance\r
3100 data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
3101--*/\r
3102{\r
3103 UINTN Count;\r
3104 LIST_ENTRY *NewPosition;\r
3105 UI_MENU_OPTION *MenuOption;\r
3106 UINTN PadLineNumber;\r
3107\r
3108 PadLineNumber = 0;\r
3109 NewPosition = *CurrentPosition;\r
3110 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3111\r
3112 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3113 //\r
3114 // Calculate the distance from current position to the last Date/Time op-code.\r
3115 //\r
3116 Count = 0;\r
3117 while (MenuOption->ThisTag->NumberOfLines == 0) {\r
3118 Count++;\r
3119 NewPosition = NewPosition->ForwardLink;\r
3120 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3121 PadLineNumber = 1;\r
3122 }\r
3123\r
3124 NewPosition = *CurrentPosition;\r
3125 if (DirectionUp) {\r
3126 //\r
3127 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
3128 // to be one that back to the previous set of op-codes, we need to advance to the first\r
3129 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate\r
3130 // checking can be done.\r
3131 //\r
3132 while (Count++ < 2) {\r
3133 NewPosition = NewPosition->BackLink;\r
3134 }\r
3135 } else {\r
3136 //\r
3137 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3138 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3139 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate\r
3140 // checking can be done.\r
3141 //\r
3142 while (Count-- > 0) {\r
3143 NewPosition = NewPosition->ForwardLink;\r
3144 }\r
3145 }\r
3146\r
3147 *CurrentPosition = NewPosition;\r
3148 }\r
3149\r
3150 return PadLineNumber;\r
3151}\r