]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c
UEFI HII: Merge UEFI HII support changes from branch.
[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
f79314fa 364 IN FRAMEWORK_EFI_HII_HANDLE Handle,\r
103b6520 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
f79314fa 404 IN FRAMEWORK_EFI_HII_HANDLE Handle,\r
103b6520 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
f79314fa 801 gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & FRAMEWORK_EFI_IFR_FLAG_RESET_REQUIRED) == FRAMEWORK_EFI_IFR_FLAG_RESET_REQUIRED));\r
103b6520 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
f79314fa 860 FRAMEWORK_EFI_IFR_BINARY *IfrBinary;\r
861 FRAMEWORK_EFI_IFR_BINARY *PreviousIfrBinary;\r
103b6520 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
f79314fa 903 for (Index = 0; FormTags->Tags[Index].Operand != FRAMEWORK_EFI_IFR_END_FORM_OP; Index++) {\r
103b6520 904 //\r
905 // It is more than likely that the very last page will contain an end formset\r
906 //\r
f79314fa 907 if (FormTags->Tags[Index].Operand == FRAMEWORK_EFI_IFR_END_FORM_SET_OP) {\r
103b6520 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
f79314fa 1096 if (Tag->Flags & FRAMEWORK_EFI_IFR_FLAG_LATE_CHECK) {\r
103b6520 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
f79314fa 1133 IN FRAMEWORK_EFI_HII_HANDLE Handle\r
103b6520 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
f79314fa 1158 if ((Tag->Operand == FRAMEWORK_EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) {\r
103b6520 1159 String = GetToken (Tag->TextTwo, Handle);\r
1160 Size = StrLen (String);\r
1161 FreePool (String);\r
1162 }\r
1163\r
f79314fa 1164 if ((Tag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP) ||\r
1165 (Tag->Operand == FRAMEWORK_EFI_IFR_REF_OP) ||\r
1166 (Tag->Operand == FRAMEWORK_EFI_IFR_PASSWORD_OP) ||\r
1167 (Tag->Operand == FRAMEWORK_EFI_IFR_STRING_OP) ||\r
1168 (Tag->Operand == FRAMEWORK_EFI_IFR_INVENTORY_OP) ||\r
103b6520 1169 //\r
1170 // Allow a wide display if text op-code and no secondary text op-code\r
1171 //\r
f79314fa 1172 ((Tag->Operand == FRAMEWORK_EFI_IFR_TEXT_OP) && (Size == 0x0000))\r
103b6520 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
f79314fa 1288 IN FRAMEWORK_EFI_IFR_DATA_ARRAY *PageData,\r
103b6520 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
f79314fa 1379 OUT FRAMEWORK_EFI_IFR_DATA_ARRAY *PageData\r
103b6520 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
f79314fa 1391 PageData - A pointer to the FRAMEWORK_EFI_IFR_DATA_ARRAY.\r
103b6520 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
f79314fa 1436 FRAMEWORK_EFI_IFR_BINARY *IfrBinary;\r
103b6520 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
c3e02ca5 1444 EFI_VARIABLE_DEFINITION *UiDefaultVarDef; // Only used in CfUiDefault State\r
103b6520 1445 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;\r
1446 EFI_HII_VARIABLE_PACK_LIST *NvMapListHead;\r
1447 EFI_HII_VARIABLE_PACK_LIST *NvMapListNode;\r
1448 VOID *NvMap;\r
1449 UINTN NvMapSize;\r
1450\r
1451 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1452\r
1453 VariableDefinition = NULL;\r
1454 Status = EFI_SUCCESS;\r
1455 FormattedString = NULL;\r
1456 OptionString = NULL;\r
1457 ScreenOperation = UiNoOperation;\r
1458 NewLine = TRUE;\r
1459 FormCallback = NULL;\r
1460 FileFormTags = NULL;\r
1461 OutputString = NULL;\r
1462 gUpArrow = FALSE;\r
1463 gDownArrow = FALSE;\r
1464 SkipValue = 0;\r
1465 OldSkipValue = 0;\r
1466 MenuRefreshEntry = gMenuRefreshHead;\r
1467 OldMenuRefreshEntry = gMenuRefreshHead;\r
1468 NextMenuOption = NULL;\r
1469 PreviousMenuOption = NULL;\r
1470 SavedMenuOption = NULL;\r
1471 IfrBinary = NULL;\r
1472 NvMap = NULL;\r
1473 NvMapSize = 0;\r
1474\r
1475 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1476\r
1477 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
1478 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1479 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1480 } else {\r
1481 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1482 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1483 }\r
1484\r
1485 if (SubMenu) {\r
1486 Col = LocalScreen.LeftColumn;\r
1487 } else {\r
1488 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
1489 }\r
1490\r
1491 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1492\r
1493 TopOfScreen = Menu.ForwardLink;\r
1494 Repaint = TRUE;\r
1495 MenuOption = NULL;\r
1496\r
1497 //\r
1498 // Get user's selection\r
1499 //\r
1500 Selection = NULL;\r
1501 NewPos = Menu.ForwardLink;\r
1502 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1503\r
1504 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1505\r
1506 ControlFlag = CfInitialization;\r
1507\r
1508 while (TRUE) {\r
1509 switch (ControlFlag) {\r
1510 case CfInitialization:\r
1511 ControlFlag = CfCheckSelection;\r
1512 if (gExitRequired) {\r
1513 ScreenOperation = UiReset;\r
1514 ControlFlag = CfScreenOperation;\r
1515 } else if (gSaveRequired) {\r
1516 ScreenOperation = UiSave;\r
1517 ControlFlag = CfScreenOperation;\r
1518 } else if (IsListEmpty (&Menu)) {\r
1519 ControlFlag = CfReadKey;\r
1520 }\r
1521 break;\r
1522\r
1523 case CfCheckSelection:\r
1524 if (Selection != NULL) {\r
1525 ControlFlag = CfExit;\r
1526 } else {\r
1527 ControlFlag = CfRepaint;\r
1528 }\r
1529\r
1530 FileFormTags = FileFormTagsHead;\r
1531 break;\r
1532\r
1533 case CfRepaint:\r
1534 ControlFlag = CfRefreshHighLight;\r
1535\r
1536 if (Repaint) {\r
1537 //\r
1538 // Display menu\r
1539 //\r
1540 SavedMenuOption = MenuOption;\r
1541 gDownArrow = FALSE;\r
1542 gUpArrow = FALSE;\r
1543 Row = TopRow;\r
1544\r
1545 Temp = SkipValue;\r
1546 Temp2 = SkipValue;\r
1547\r
1548 ClearLines (\r
1549 LocalScreen.LeftColumn,\r
1550 LocalScreen.RightColumn,\r
1551 TopRow - SCROLL_ARROW_HEIGHT,\r
1552 BottomRow + SCROLL_ARROW_HEIGHT,\r
1553 FIELD_TEXT | FIELD_BACKGROUND\r
1554 );\r
1555\r
1556 while (gMenuRefreshHead != NULL) {\r
1557 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
1558\r
1559 FreePool (gMenuRefreshHead);\r
1560\r
1561 gMenuRefreshHead = OldMenuRefreshEntry;\r
1562 }\r
1563\r
1564 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
1565 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1566 MenuOption->Row = Row;\r
1567 OriginalRow = Row;\r
1568 MenuOption->Col = Col;\r
1569 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1570\r
1571 if (SubMenu) {\r
1572 if (MenuOption->ThisTag->GrayOut) {\r
1573 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1574 } else {\r
f79314fa 1575 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP) {\r
103b6520 1576 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1577 }\r
1578 }\r
1579\r
1580 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1581\r
1582 OriginalRow = Row;\r
1583\r
1584 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1585 if ((Temp == 0) && (Row <= BottomRow)) {\r
1586 PrintStringAt (Col, Row, OutputString);\r
1587 }\r
1588 //\r
1589 // If there is more string to process print on the next row and increment the Skip value\r
1590 //\r
1591 if (StrLen (&MenuOption->Description[Index])) {\r
1592 if (Temp == 0) {\r
1593 Row++;\r
1594 }\r
1595 }\r
1596\r
1597 FreePool (OutputString);\r
1598 if (Temp != 0) {\r
1599 Temp--;\r
1600 }\r
1601 }\r
1602\r
1603 Temp = 0;\r
1604\r
1605 Row = OriginalRow;\r
1606\r
1607 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1608 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1609\r
1610 if (OptionString != NULL) {\r
f79314fa 1611 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP ||\r
1612 MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP\r
103b6520 1613 ) {\r
1614 //\r
1615 // If leading spaces on OptionString - remove the spaces\r
1616 //\r
1617 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1618 MenuOption->OptCol++;\r
1619 }\r
1620\r
1621 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1622 OptionString[Count] = OptionString[Index];\r
1623 Count++;\r
1624 }\r
1625\r
1626 OptionString[Count] = CHAR_NULL;\r
1627 }\r
1628\r
1629 //\r
1630 // If this is a date or time op-code and is used to reflect an RTC, register the op-code\r
1631 //\r
f79314fa 1632 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP ||\r
1633 MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP) &&\r
103b6520 1634 (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {\r
1635\r
1636 if (gMenuRefreshHead == NULL) {\r
1637 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1638 ASSERT (MenuRefreshEntry != NULL);\r
1639 MenuRefreshEntry->MenuOption = MenuOption;\r
1640 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1641 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1642 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1643 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1644 gMenuRefreshHead = MenuRefreshEntry;\r
1645 } else {\r
1646 //\r
1647 // Advance to the last entry\r
1648 //\r
1649 for (MenuRefreshEntry = gMenuRefreshHead;\r
1650 MenuRefreshEntry->Next != NULL;\r
1651 MenuRefreshEntry = MenuRefreshEntry->Next\r
1652 )\r
1653 ;\r
1654 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1655 ASSERT (MenuRefreshEntry->Next != NULL);\r
1656 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1657 MenuRefreshEntry->MenuOption = MenuOption;\r
1658 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1659 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1660 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1661 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1662 }\r
1663 }\r
1664\r
1665 Width = (UINT16) gOptionBlockWidth;\r
1666\r
1667 OriginalRow = Row;\r
1668\r
1669 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1670 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1671 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1672 }\r
1673 //\r
1674 // If there is more string to process print on the next row and increment the Skip value\r
1675 //\r
1676 if (StrLen (&OptionString[Index])) {\r
1677 if (Temp2 == 0) {\r
1678 Row++;\r
1679 //\r
1680 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1681 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1682 // some testing to ensure we are keeping this in-sync.\r
1683 //\r
1684 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1685 //\r
1686 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1687 MenuOption->Skip++;\r
1688 }\r
1689 }\r
1690 }\r
1691\r
1692 FreePool (OutputString);\r
1693 if (Temp2 != 0) {\r
1694 Temp2--;\r
1695 }\r
1696 }\r
1697\r
1698 Temp2 = 0;\r
1699 Row = OriginalRow;\r
1700 }\r
1701 //\r
1702 // If this is a text op with secondary text information\r
1703 //\r
f79314fa 1704 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {\r
103b6520 1705 StringPtr = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle);\r
1706\r
1707 Width = (UINT16) gOptionBlockWidth;\r
1708\r
1709 OriginalRow = Row;\r
1710\r
1711 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1712 if ((Temp == 0) && (Row <= BottomRow)) {\r
1713 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1714 }\r
1715 //\r
1716 // If there is more string to process print on the next row and increment the Skip value\r
1717 //\r
1718 if (StrLen (&StringPtr[Index])) {\r
1719 if (Temp2 == 0) {\r
1720 Row++;\r
1721 //\r
1722 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1723 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1724 // some testing to ensure we are keeping this in-sync.\r
1725 //\r
1726 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1727 //\r
1728 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1729 MenuOption->Skip++;\r
1730 }\r
1731 }\r
1732 }\r
1733\r
1734 FreePool (OutputString);\r
1735 if (Temp2 != 0) {\r
1736 Temp2--;\r
1737 }\r
1738 }\r
1739\r
1740 Row = OriginalRow;\r
1741 FreePool (StringPtr);\r
1742 }\r
1743 } else {\r
1744 //\r
1745 // For now, assume left-justified 72 width max setup entries\r
1746 //\r
1747 PrintStringAt (Col, Row, MenuOption->Description);\r
1748 }\r
1749 //\r
1750 // Tracker 6210 - need to handle the bottom of the display\r
1751 //\r
1752 if (MenuOption->Skip > 1) {\r
1753 Row += MenuOption->Skip - SkipValue;\r
1754 SkipValue = 0;\r
1755 } else {\r
1756 Row += MenuOption->Skip;\r
1757 }\r
1758\r
1759 if (Row > BottomRow) {\r
1760 if (!ValueIsScroll (FALSE, Link)) {\r
1761 gDownArrow = TRUE;\r
1762 }\r
1763\r
1764 Row = BottomRow + 1;\r
1765 break;\r
1766 }\r
1767 }\r
1768\r
1769 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
1770 gUpArrow = TRUE;\r
1771 }\r
1772\r
1773 if (gUpArrow) {\r
1774 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1775 PrintAt (\r
1776 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1777 TopRow - SCROLL_ARROW_HEIGHT,\r
1778 (CHAR16 *) L"%c",\r
1779 ARROW_UP\r
1780 );\r
1781 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1782 }\r
1783\r
1784 if (gDownArrow) {\r
1785 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1786 PrintAt (\r
1787 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1788 BottomRow + SCROLL_ARROW_HEIGHT,\r
1789 (CHAR16 *) L"%c",\r
1790 ARROW_DOWN\r
1791 );\r
1792 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1793 }\r
1794\r
1795 if (SavedMenuOption != NULL) {\r
1796 MenuOption = SavedMenuOption;\r
1797 }\r
1798 }\r
1799 break;\r
1800\r
1801 case CfRefreshHighLight:\r
1802 ControlFlag = CfUpdateHelpString;\r
1803 //\r
1804 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
1805 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
1806 //\r
1807 SavedValue = Repaint;\r
1808 Repaint = FALSE;\r
1809\r
1810 if (NewPos != NULL) {\r
1811 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1812 if (SubMenu) {\r
1813 if (gLastOpr && (gEntryNumber != -1)) {\r
1814 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1815 if (gEntryNumber != MenuOption->EntryNumber) {\r
1816 ScreenOperation = UiDown;\r
1817 ControlFlag = CfScreenOperation;\r
1818 break;\r
1819 } else {\r
1820 gLastOpr = FALSE;\r
1821 }\r
1822 }\r
1823\r
1824 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1825 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1826 if (OptionString != NULL) {\r
f79314fa 1827 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP ||\r
1828 MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP\r
103b6520 1829 ) {\r
1830 //\r
1831 // If leading spaces on OptionString - remove the spaces\r
1832 //\r
1833 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1834 ;\r
1835\r
1836 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1837 OptionString[Count] = OptionString[Index];\r
1838 Count++;\r
1839 }\r
1840\r
1841 OptionString[Count] = CHAR_NULL;\r
1842 }\r
1843\r
1844 Width = (UINT16) gOptionBlockWidth;\r
1845\r
1846 OriginalRow = MenuOption->Row;\r
1847\r
1848 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1849 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1850 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1851 }\r
1852 //\r
1853 // If there is more string to process print on the next row and increment the Skip value\r
1854 //\r
1855 if (StrLen (&OptionString[Index])) {\r
1856 MenuOption->Row++;\r
1857 }\r
1858\r
1859 FreePool (OutputString);\r
1860 }\r
1861\r
1862 MenuOption->Row = OriginalRow;\r
1863 } else {\r
1864 if (NewLine) {\r
1865 if (MenuOption->ThisTag->GrayOut) {\r
1866 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1867 } else {\r
f79314fa 1868 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP) {\r
103b6520 1869 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1870 }\r
1871 }\r
1872\r
1873 OriginalRow = MenuOption->Row;\r
1874 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1875\r
1876 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1877 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1878 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1879 }\r
1880 //\r
1881 // If there is more string to process print on the next row and increment the Skip value\r
1882 //\r
1883 if (StrLen (&MenuOption->Description[Index])) {\r
1884 MenuOption->Row++;\r
1885 }\r
1886\r
1887 FreePool (OutputString);\r
1888 }\r
1889\r
1890 MenuOption->Row = OriginalRow;\r
1891 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1892 }\r
1893 }\r
1894 } else {\r
1895 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1896 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
1897 }\r
1898\r
1899 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1900\r
1901 if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {\r
1902 ScreenOperation = UiDown;\r
1903 ControlFlag = CfScreenOperation;\r
1904 break;\r
1905 } else {\r
1906 gPriorMenuEntry = 0;\r
1907 }\r
1908 //\r
1909 // This is only possible if we entered this page and the first menu option is\r
1910 // a "non-menu" item. In that case, force it UiDown\r
1911 //\r
f79314fa 1912 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
103b6520 1913 //\r
1914 // If we previously hit an UP command and we are still sitting on a text operation\r
1915 // we must continue going up\r
1916 //\r
1917 if (ScreenOperation == UiUp) {\r
1918 ControlFlag = CfScreenOperation;\r
1919 break;\r
1920 } else {\r
1921 ScreenOperation = UiDown;\r
1922 ControlFlag = CfScreenOperation;\r
1923 break;\r
1924 }\r
1925 }\r
1926 //\r
1927 // Set reverse attribute\r
1928 //\r
1929 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
1930 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1931\r
1932 //\r
1933 // Assuming that we have a refresh linked-list created, lets annotate the\r
1934 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
1935 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
1936 //\r
1937 if (gMenuRefreshHead != NULL) {\r
1938 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
1939 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1940 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
1941 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
1942 }\r
1943 }\r
1944 }\r
1945\r
1946 if (SubMenu) {\r
1947 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1948 if (OptionString != NULL) {\r
f79314fa 1949 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP ||\r
1950 MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP\r
103b6520 1951 ) {\r
1952 //\r
1953 // If leading spaces on OptionString - remove the spaces\r
1954 //\r
1955 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1956 ;\r
1957\r
1958 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1959 OptionString[Count] = OptionString[Index];\r
1960 Count++;\r
1961 }\r
1962\r
1963 OptionString[Count] = CHAR_NULL;\r
1964 }\r
1965 Width = (UINT16) gOptionBlockWidth;\r
1966\r
1967 OriginalRow = MenuOption->Row;\r
1968\r
1969 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1970 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1971 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1972 }\r
1973 //\r
1974 // If there is more string to process print on the next row and increment the Skip value\r
1975 //\r
1976 if (StrLen (&OptionString[Index])) {\r
1977 MenuOption->Row++;\r
1978 }\r
1979\r
1980 FreePool (OutputString);\r
1981 }\r
1982\r
1983 MenuOption->Row = OriginalRow;\r
1984 } else {\r
1985 if (NewLine) {\r
1986 OriginalRow = MenuOption->Row;\r
1987\r
1988 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1989\r
1990 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1991 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1992 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1993 }\r
1994 //\r
1995 // If there is more string to process print on the next row and increment the Skip value\r
1996 //\r
1997 if (StrLen (&MenuOption->Description[Index])) {\r
1998 MenuOption->Row++;\r
1999 }\r
2000\r
2001 FreePool (OutputString);\r
2002 }\r
2003\r
2004 MenuOption->Row = OriginalRow;\r
2005\r
2006 }\r
2007 }\r
2008\r
2009 if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||\r
2010 ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||\r
2011 (ScreenOperation == UiNoOperation)\r
2012 ) {\r
2013 UpdateKeyHelp (MenuOption, FALSE);\r
2014 }\r
2015 } else {\r
2016 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2017 }\r
2018 //\r
2019 // Clear reverse attribute\r
2020 //\r
2021 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2022 }\r
2023 //\r
2024 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2025 // if we didn't break halfway when process CfRefreshHighLight.\r
2026 //\r
2027 Repaint = SavedValue;\r
2028 break;\r
2029\r
2030 case CfUpdateHelpString:\r
2031 ControlFlag = CfPrepareToReadKey;\r
2032\r
2033 if (SubMenu &&\r
2034 (Repaint || NewLine ||\r
f79314fa 2035 (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) ||\r
2036 (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP)) &&\r
103b6520 2037 !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
2038 //\r
2039 // Don't print anything if it is a NULL help token\r
2040 //\r
2041 if (MenuOption->ThisTag->Help == 0x00000000) {\r
2042 StringPtr = (CHAR16 *) L"\0";\r
2043 } else {\r
2044 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2045 }\r
2046\r
2047 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2048\r
2049 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2050\r
2051 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2052 //\r
2053 // Pad String with spaces to simulate a clearing of the previous line\r
2054 //\r
2055 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
2056 StrCat (&FormattedString[Index * gHelpBlockWidth * 2], (CHAR16 *) L" ");\r
2057 }\r
2058\r
2059 PrintStringAt (\r
2060 LocalScreen.RightColumn - gHelpBlockWidth,\r
2061 Index + TopRow,\r
2062 &FormattedString[Index * gHelpBlockWidth * 2]\r
2063 );\r
2064 }\r
2065 }\r
2066 //\r
2067 // Reset this flag every time we finish using it.\r
2068 //\r
2069 Repaint = FALSE;\r
2070 NewLine = FALSE;\r
2071 break;\r
2072\r
2073 case CfPrepareToReadKey:\r
2074 ControlFlag = CfReadKey;\r
2075\r
2076 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
2077 FileFormTags = FileFormTags->NextFile;\r
2078 }\r
2079\r
2080 ScreenOperation = UiNoOperation;\r
2081\r
2082 Status = gBS->HandleProtocol (\r
2083 (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,\r
2084 &gEfiFormCallbackProtocolGuid,\r
2085 (VOID **) &FormCallback\r
2086 );\r
2087\r
2088 break;\r
2089\r
2090 case CfReadKey:\r
2091 ControlFlag = CfScreenOperation;\r
2092\r
2093 OriginalTimeOut = FrontPageTimeOutValue;\r
2094 do {\r
2095 if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {\r
2096 //\r
2097 // Remember that if set to 0, must immediately boot an option\r
2098 //\r
2099 if (FrontPageTimeOutValue == 0) {\r
2100 FrontPageTimeOutValue = 0xFFFF;\r
2101 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2102 if (EFI_ERROR (Status)) {\r
2103 Status = EFI_TIMEOUT;\r
2104 }\r
2105 break;\r
2106 }\r
2107\r
2108 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);\r
2109 if (Status == EFI_TIMEOUT) {\r
f79314fa 2110 FRAMEWORK_EFI_IFR_DATA_ENTRY *DataEntry;\r
103b6520 2111\r
f79314fa 2112 DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
103b6520 2113\r
2114 PageData->EntryCount = 1;\r
2115 Count = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);\r
2116 CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));\r
2117\r
2118 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2119 FormCallback->Callback (\r
2120 FormCallback,\r
2121 0xFFFF,\r
f79314fa 2122 (FRAMEWORK_EFI_IFR_DATA_ARRAY *) PageData,\r
103b6520 2123 NULL\r
2124 );\r
2125 }\r
2126 //\r
2127 // Count down 1 second\r
2128 //\r
2129 FrontPageTimeOutValue--;\r
2130\r
2131 } else {\r
2132 ASSERT (!EFI_ERROR (Status));\r
2133 PageData->EntryCount = 0;\r
2134 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2135 FormCallback->Callback (\r
2136 FormCallback,\r
2137 0xFFFE,\r
f79314fa 2138 (FRAMEWORK_EFI_IFR_DATA_ARRAY *) PageData,\r
103b6520 2139 NULL\r
2140 );\r
2141 }\r
2142\r
2143 FrontPageTimeOutValue = 0xFFFF;\r
2144 }\r
2145 } else {\r
2146 //\r
2147 // Wait for user's selection, no auto boot\r
2148 //\r
2149 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
2150 }\r
2151 } while (Status == EFI_TIMEOUT);\r
2152\r
2153 if (gFirstIn) {\r
2154 gFirstIn = FALSE;\r
2155 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2156 DisableQuietBoot ();\r
2157 }\r
2158\r
2159 if (Status == EFI_TIMEOUT) {\r
2160 Key.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
2161 } else {\r
2162 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2163 //\r
2164 // if we encounter error, continue to read another key in.\r
2165 //\r
2166 if (EFI_ERROR (Status)) {\r
2167 ControlFlag = CfReadKey;\r
2168 continue;\r
2169 }\r
2170 }\r
2171\r
2172 switch (Key.UnicodeChar) {\r
2173 case CHAR_CARRIAGE_RETURN:\r
2174 Selection = MenuOption;\r
2175 ScreenOperation = UiSelect;\r
2176 gDirection = 0;\r
2177 break;\r
2178\r
2179 //\r
2180 // We will push the adjustment of these numeric values directly to the input handler\r
2181 //\r
2182 case '+':\r
2183 case '-':\r
f79314fa 2184 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP)) {\r
103b6520 2185\r
2186 if (Key.UnicodeChar == '+') {\r
2187 gDirection = SCAN_RIGHT;\r
2188 } else {\r
2189 gDirection = SCAN_LEFT;\r
2190 }\r
2191\r
2192 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);\r
2193 }\r
2194 break;\r
2195\r
2196 case '^':\r
2197 ScreenOperation = UiUp;\r
2198 break;\r
2199\r
2200 case 'V':\r
2201 case 'v':\r
2202 ScreenOperation = UiDown;\r
2203 break;\r
2204\r
2205 case ' ':\r
2206 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
2207 if (SubMenu) {\r
f79314fa 2208 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {\r
103b6520 2209 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2210 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2211 Selection = MenuOption;\r
2212 ScreenOperation = UiSelect;\r
2213 }\r
2214 }\r
2215 }\r
2216 break;\r
2217\r
2218 case CHAR_NULL:\r
2219 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
2220 ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
2221 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
2222 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2223 ) {\r
2224 //\r
2225 // If the function key has been disabled, just ignore the key.\r
2226 //\r
2227 } else {\r
2228 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2229 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2230 if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) {\r
2231 if (SubMenu) {\r
2232 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2233 }\r
2234 } else {\r
2235 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2236 }\r
2237 }\r
2238 }\r
2239 }\r
2240 break;\r
2241 }\r
2242 break;\r
2243\r
2244 case CfScreenOperation:\r
2245 IfrBinary = gBinaryDataHead;\r
2246\r
2247 //\r
2248 // Advance to the Ifr we are using\r
2249 //\r
2250 for (Index = 0; Index < gActiveIfr; Index++) {\r
2251 IfrBinary = IfrBinary->Next;\r
2252 }\r
2253\r
2254 if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
2255 //\r
2256 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
2257 // ignore the selection and go back to reading keys.\r
2258 //\r
2259 if (IsListEmpty (&Menu)) {\r
2260 ControlFlag = CfReadKey;\r
2261 break;\r
2262 }\r
2263 //\r
2264 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2265 //\r
2266 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
2267 NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
f79314fa 2268 if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != FRAMEWORK_EFI_IFR_SUBTITLE_OP)) {\r
103b6520 2269 break;\r
2270 }\r
2271 }\r
2272\r
2273 if (Link == &Menu) {\r
2274 ControlFlag = CfPrepareToReadKey;\r
2275 break;\r
2276 }\r
2277 }\r
2278\r
2279 for (Index = 0;\r
2280 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2281 Index++\r
2282 ) {\r
2283 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2284 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2285 }\r
2286 }\r
2287\r
2288 break;\r
2289\r
2290 case CfUiPrevious:\r
2291 ControlFlag = CfCheckSelection;\r
2292 //\r
2293 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2294 //\r
2295 if (MenuOption != NULL) {\r
2296 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2297 Selection = NULL;\r
2298 Repaint = TRUE;\r
2299 break;\r
2300 }\r
2301 }\r
2302\r
2303 if (IsListEmpty (&gMenuList)) {\r
2304 Selection = NULL;\r
2305 if (IsListEmpty (&Menu)) {\r
2306 ControlFlag = CfReadKey;\r
2307 }\r
2308 break;\r
2309 }\r
2310\r
2311 gLastOpr = TRUE;\r
2312\r
2313 while (gMenuRefreshHead != NULL) {\r
2314 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
2315\r
2316 FreePool (gMenuRefreshHead);\r
2317\r
2318 gMenuRefreshHead = OldMenuRefreshEntry;\r
2319 }\r
2320 //\r
2321 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag\r
2322 //\r
2323 if (SubMenu) {\r
2324 UiRemoveMenuListEntry (MenuOption, &Selection);\r
2325 Selection->Previous = TRUE;\r
2326 UiFreeMenu ();\r
2327 UiInitMenu ();\r
2328 }\r
2329\r
2330 gActiveIfr = Selection->IfrNumber;\r
2331 return Selection;\r
2332\r
2333 case CfUiSelect:\r
2334 ControlFlag = CfCheckSelection;\r
2335\r
2336 ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);\r
2337\r
2338 if (SubMenu) {\r
f79314fa 2339 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TEXT_OP &&\r
2340 !(MenuOption->ThisTag->Flags & FRAMEWORK_EFI_IFR_FLAG_INTERACTIVE)) ||\r
103b6520 2341 (MenuOption->ThisTag->GrayOut) ||\r
f79314fa 2342 (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) ||\r
2343 (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP)) {\r
103b6520 2344 Selection = NULL;\r
2345 break;\r
2346 }\r
2347\r
2348 NewLine = TRUE;\r
2349 UpdateKeyHelp (MenuOption, TRUE);\r
2350 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);\r
2351\r
2352 if (EFI_ERROR (Status)) {\r
2353 Selection = NULL;\r
2354 Repaint = TRUE;\r
2355 break;\r
2356 }\r
2357\r
2358 if (OptionString != NULL) {\r
2359 PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);\r
2360 }\r
2361\r
f79314fa 2362 if (MenuOption->ThisTag->Flags & FRAMEWORK_EFI_IFR_FLAG_INTERACTIVE) {\r
103b6520 2363 Selection = MenuOption;\r
2364 }\r
2365\r
2366 if (Selection == NULL) {\r
2367 break;\r
2368 }\r
2369\r
2370 Location = (UINT8 *) &PageData->EntryCount;\r
2371\r
2372 //\r
2373 // If not a goto, dump single piece of data, otherwise dump everything\r
2374 //\r
f79314fa 2375 if (Selection->ThisTag->Operand == FRAMEWORK_EFI_IFR_REF_OP) {\r
103b6520 2376 //\r
2377 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2378 //\r
2379 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2380 Selection = NULL;\r
2381 Repaint = TRUE;\r
2382 break;\r
2383 }\r
2384\r
2385 UiAddMenuListEntry (Selection);\r
2386 gPriorMenuEntry = 0;\r
2387\r
2388 //\r
2389 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious\r
2390 //\r
2391 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
2392 UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;\r
2393\r
2394 gLastOpr = FALSE;\r
2395\r
2396 //\r
2397 // Rewind to the beginning of the menu\r
2398 //\r
2399 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2400 ;\r
2401\r
2402 //\r
2403 // Get Total Count of Menu entries\r
2404 //\r
2405 for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {\r
2406 Count++;\r
2407 }\r
2408 //\r
2409 // Rewind to the beginning of the menu\r
2410 //\r
2411 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2412 ;\r
2413\r
2414 //\r
2415 // Copy the number of entries being described to the PageData location\r
2416 //\r
2417 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2418\r
2419 for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {\r
2420\r
2421 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2422 Location[Index] = MenuOption->ThisTag->Operand;\r
2423 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2424 CopyMem (\r
2425 &Location[Index + 4],\r
2426 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2427 MenuOption->ThisTag->StorageWidth\r
2428 );\r
2429 NewPos = NewPos->ForwardLink;\r
2430 }\r
2431 } else {\r
2432\r
2433 gPriorMenuEntry = MenuOption->EntryNumber;\r
2434\r
2435 Count = 1;\r
2436\r
2437 //\r
2438 // Copy the number of entries being described to the PageData location\r
2439 //\r
2440 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2441\r
2442 //\r
2443 // Start at PageData[4] since the EntryCount is a UINT32\r
2444 //\r
2445 Index = 4;\r
2446\r
2447 //\r
2448 // Copy data to destination\r
2449 //\r
2450 Location[Index] = MenuOption->ThisTag->Operand;\r
2451 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2452 CopyMem (\r
2453 &Location[Index + 4],\r
2454 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2455 MenuOption->ThisTag->StorageWidth\r
2456 );\r
2457 }\r
2458 }\r
2459 break;\r
2460\r
2461 case CfUiReset:\r
2462 ControlFlag = CfCheckSelection;\r
2463 gLastOpr = FALSE;\r
2464 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
2465 break;\r
2466 }\r
2467 //\r
2468 // If NV flag is up, prompt user\r
2469 //\r
2470 if (gNvUpdateRequired) {\r
2471 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2472\r
2473 YesResponse = gYesResponse[0];\r
2474 NoResponse = gNoResponse[0];\r
2475\r
2476 do {\r
2477 CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
2478 } while\r
2479 (\r
2480 (Key.ScanCode != SCAN_ESC) &&\r
2481 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
2482 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
2483 );\r
2484\r
2485 //\r
2486 // If the user hits the YesResponse key\r
2487 //\r
2488 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
2489 } else {\r
2490 Repaint = TRUE;\r
2491 NewLine = TRUE;\r
2492 break;\r
2493 }\r
2494 }\r
2495 //\r
2496 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2497 //\r
2498 if (MenuOption != NULL) {\r
2499 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2500 Selection = NULL;\r
2501 Repaint = TRUE;\r
2502 NewLine = TRUE;\r
2503 break;\r
2504 }\r
2505 }\r
2506\r
2507 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2508 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
2509\r
2510 if (SubMenu) {\r
2511 UiFreeMenuList ();\r
2512 gST->ConOut->ClearScreen (gST->ConOut);\r
2513 return NULL;\r
2514 }\r
2515\r
2516 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2517 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2518\r
2519 if (IfrBinary->UnRegisterOnExit) {\r
2520 Hii->RemovePack (Hii, MenuOption->Handle);\r
2521 }\r
2522\r
2523 UiFreeMenu ();\r
2524\r
2525 //\r
2526 // Clean up the allocated data buffers\r
2527 //\r
2528 FreeData (FileFormTagsHead, FormattedString, OptionString);\r
2529\r
2530 gST->ConOut->ClearScreen (gST->ConOut);\r
2531 return NULL;\r
2532\r
2533 case CfUiLeft:\r
2534 ControlFlag = CfCheckSelection;\r
f79314fa 2535 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP)) {\r
103b6520 2536 if (MenuOption->Skip == 1) {\r
2537 //\r
2538 // In the tail of the Date/Time op-code set, go left.\r
2539 //\r
2540 NewPos = NewPos->BackLink;\r
2541 } else {\r
2542 //\r
2543 // In the middle of the Data/Time op-code set, go left.\r
2544 //\r
2545 NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2546 if (NextMenuOption->Skip == 1) {\r
2547 NewPos = NewPos->BackLink;\r
2548 }\r
2549 }\r
2550 }\r
2551 break;\r
2552\r
2553 case CfUiRight:\r
2554 ControlFlag = CfCheckSelection;\r
2555 if ((MenuOption->Skip == 0) &&\r
f79314fa 2556 ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP))\r
103b6520 2557 ) {\r
2558 //\r
2559 // We are in the head or middle of the Date/Time op-code set, advance right.\r
2560 //\r
2561 NewPos = NewPos->ForwardLink;\r
2562 }\r
2563 break;\r
2564\r
2565 case CfUiUp:\r
2566 ControlFlag = CfCheckSelection;\r
2567\r
2568 if (NewPos->BackLink != &Menu) {\r
2569 NewLine = TRUE;\r
2570 //\r
2571 // Adjust Date/Time position before we advance forward.\r
2572 //\r
2573 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2574\r
2575 //\r
2576 // Caution that we have already rewind to the top, don't go backward in this situation.\r
2577 //\r
2578 if (NewPos->BackLink != &Menu) {\r
2579 NewPos = NewPos->BackLink;\r
2580 }\r
2581\r
2582 PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2583\r
2584 //\r
2585 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
2586 // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
2587 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2588 // checking can be done.\r
2589 //\r
2590 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);\r
2591\r
2592 if (SubMenu) {\r
2593 //\r
2594 // If the previous MenuOption contains a display-only op-code, skip to the next one\r
2595 //\r
f79314fa 2596 if (PreviousMenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {\r
103b6520 2597 //\r
2598 // This is ok as long as not at the end of the list\r
2599 //\r
2600 if (NewPos->BackLink == &Menu) {\r
2601 //\r
2602 // If we are at the start of the list, then this list must start with a display only\r
2603 // piece of data, so do not allow the backward motion\r
2604 //\r
2605 ScreenOperation = UiDown;\r
2606\r
2607 if (PreviousMenuOption->Row <= TopRow) {\r
2608 if (TopOfScreen->BackLink != &Menu) {\r
2609 TopOfScreen = TopOfScreen->BackLink;\r
2610 Repaint = TRUE;\r
2611 }\r
2612 }\r
2613\r
2614 UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);\r
2615 break;\r
2616 }\r
2617 }\r
2618 }\r
2619 //\r
2620 // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
2621 // don't worry about a redraw.\r
2622 //\r
2623 if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||\r
2624 (PreviousMenuOption->Skip > MenuOption->Row)\r
2625 ) {\r
2626 do {\r
2627 if (TopOfScreen->BackLink == &Menu) {\r
2628 break;\r
2629 }\r
2630\r
2631 Repaint = TRUE;\r
2632\r
2633 //\r
2634 // Is the current top of screen a zero-advance op-code?\r
2635 // If so, keep moving forward till we hit a >0 advance op-code\r
2636 //\r
2637 SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2638 TopOfScreen = TopOfScreen->BackLink;\r
2639 } while (SavedMenuOption->Skip == 0);\r
2640 //\r
2641 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2642 //\r
2643 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2644 }\r
2645\r
2646 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2647 } else {\r
2648 if (SubMenu) {\r
2649 SavedMenuOption = MenuOption;\r
2650 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
f79314fa 2651 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
103b6520 2652 //\r
2653 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2654 //\r
2655 ScreenOperation = UiDown;\r
2656 ControlFlag = CfScreenOperation;\r
2657 break;\r
2658 }\r
2659\r
2660 MenuOption = SavedMenuOption;\r
2661 }\r
2662 }\r
2663 break;\r
2664\r
2665 case CfUiPageUp:\r
2666 ControlFlag = CfCheckSelection;\r
2667\r
2668 SavedListEntry = NewPos;\r
2669 Link = TopOfScreen;\r
2670 for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {\r
2671 if (Link->BackLink == &Menu) {\r
2672 TopOfScreen = Link;\r
2673 Link = SavedListEntry;\r
2674 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2675 break;\r
2676 }\r
2677\r
2678 NewLine = TRUE;\r
2679 Repaint = TRUE;\r
2680 Link = Link->BackLink;\r
2681 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2682 TopOfScreen = Link;\r
2683 SavedListEntry = Link;\r
2684 }\r
2685\r
2686 NewPos = Link;\r
2687\r
2688 //\r
2689 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2690 // Don't do this when we are already in the first page.\r
2691 //\r
2692 if (Repaint) {\r
2693 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2694 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2695 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2696 }\r
2697 break;\r
2698\r
2699 case CfUiPageDown:\r
2700 ControlFlag = CfCheckSelection;\r
2701\r
2702 SavedListEntry = NewPos;\r
2703 Link = TopOfScreen;\r
2704 NewPos = TopOfScreen;\r
2705 for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {\r
2706 if (NewPos->ForwardLink == &Menu) {\r
2707 NewPos = SavedListEntry;\r
2708 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2709 Link = TopOfScreen;\r
2710 NewLine = FALSE;\r
2711 Repaint = FALSE;\r
2712 break;\r
2713 }\r
2714\r
2715 NewLine = TRUE;\r
2716 Repaint = TRUE;\r
2717 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2718 NewPos = NewPos->ForwardLink;\r
2719 Link = NewPos;\r
2720 }\r
2721\r
2722 TopOfScreen = Link;\r
2723\r
2724 //\r
2725 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2726 // Don't do this when we are already in the last page.\r
2727 //\r
2728 if (Repaint) {\r
2729 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2730 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2731 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2732 }\r
2733 break;\r
2734\r
2735 case CfUiDown:\r
2736 ControlFlag = CfCheckSelection;\r
2737 //\r
2738 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
2739 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
2740 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2741 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
2742 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
2743 // the Date/Time op-code.\r
2744 //\r
2745 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);\r
2746\r
2747 if (NewPos->ForwardLink != &Menu) {\r
2748 NewLine = TRUE;\r
2749 NewPos = NewPos->ForwardLink;\r
2750 NextMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2751\r
2752 if (SubMenu) {\r
2753 //\r
2754 // If the next MenuOption contains a display-only op-code, skip to the next one\r
2755 // Also if the next MenuOption is date or time,\r
2756 //\r
f79314fa 2757 if (NextMenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {\r
103b6520 2758 //\r
2759 // This is ok as long as not at the end of the list\r
2760 //\r
2761 if (NewPos == &Menu) {\r
2762 //\r
2763 // If we are at the end of the list, then this list must end with a display only\r
2764 // piece of data, so do not allow the forward motion\r
2765 //\r
2766 UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);\r
2767 NewPos = NewPos->BackLink;\r
2768 ScreenOperation = UiUp;\r
2769 break;\r
2770 }\r
2771 }\r
2772 }\r
2773 //\r
2774 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
2775 //\r
2776 UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);\r
2777\r
2778 if (NextMenuOption->Skip > 1) {\r
2779 Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;\r
2780 } else {\r
2781 Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;\r
2782 }\r
2783 //\r
2784 // If we are going to scroll\r
2785 //\r
2786 if (Temp > BottomRow) {\r
2787 do {\r
2788 //\r
2789 // Is the current top of screen a zero-advance op-code?\r
2790 // If so, keep moving forward till we hit a >0 advance op-code\r
2791 //\r
2792 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2793\r
2794 //\r
2795 // If bottom op-code is more than one line or top op-code is more than one line\r
2796 //\r
2797 if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) {\r
2798 //\r
2799 // Is the bottom op-code greater than or equal in size to the top op-code?\r
2800 //\r
2801 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
2802 //\r
2803 // Skip the top op-code\r
2804 //\r
2805 TopOfScreen = TopOfScreen->ForwardLink;\r
2806 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
2807\r
2808 OldSkipValue = Difference;\r
2809\r
2810 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2811\r
2812 //\r
2813 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
2814 //\r
2815 for (;\r
2816 Difference >= (INTN) SavedMenuOption->Skip;\r
2817 Difference = Difference - (INTN) SavedMenuOption->Skip\r
2818 ) {\r
2819 //\r
2820 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
2821 //\r
2822 TopOfScreen = TopOfScreen->ForwardLink;\r
2823 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2824 if (Difference < (INTN) SavedMenuOption->Skip) {\r
2825 Difference = SavedMenuOption->Skip - Difference - 1;\r
2826 break;\r
2827 } else {\r
2828 if (Difference == (INTN) SavedMenuOption->Skip) {\r
2829 TopOfScreen = TopOfScreen->ForwardLink;\r
2830 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2831 Difference = SavedMenuOption->Skip - Difference;\r
2832 break;\r
2833 }\r
2834 }\r
2835 }\r
2836 //\r
2837 // Since we will act on this op-code in the next routine, and increment the\r
2838 // SkipValue, set the skips to one less than what is required.\r
2839 //\r
2840 SkipValue = Difference - 1;\r
2841\r
2842 } else {\r
2843 //\r
2844 // Since we will act on this op-code in the next routine, and increment the\r
2845 // SkipValue, set the skips to one less than what is required.\r
2846 //\r
2847 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
2848 }\r
2849 } else {\r
2850 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
2851 TopOfScreen = TopOfScreen->ForwardLink;\r
2852 break;\r
2853 } else {\r
2854 SkipValue = OldSkipValue;\r
2855 }\r
2856 }\r
2857 //\r
2858 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
2859 // Let's set a skip flag to smoothly scroll the top of the screen.\r
2860 //\r
2861 if (SavedMenuOption->Skip > 1) {\r
2862 if (SavedMenuOption == NextMenuOption) {\r
2863 SkipValue = 0;\r
2864 } else {\r
2865 SkipValue++;\r
2866 }\r
2867 } else {\r
2868 SkipValue = 0;\r
2869 TopOfScreen = TopOfScreen->ForwardLink;\r
2870 }\r
2871 } while (SavedMenuOption->Skip == 0);\r
2872\r
2873 Repaint = TRUE;\r
2874 OldSkipValue = SkipValue;\r
2875 }\r
2876\r
2877 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2878\r
2879 } else {\r
2880 if (SubMenu) {\r
2881 SavedMenuOption = MenuOption;\r
2882 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
f79314fa 2883 if (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
103b6520 2884 //\r
2885 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2886 //\r
2887 ScreenOperation = UiUp;\r
2888 ControlFlag = CfScreenOperation;\r
2889 break;\r
2890 }\r
2891\r
2892 MenuOption = SavedMenuOption;\r
2893 //\r
2894 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
2895 //\r
2896 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2897 }\r
2898 }\r
2899 break;\r
2900\r
2901 case CfUiSave:\r
2902 ControlFlag = CfCheckSelection;\r
2903 //\r
2904 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2905 //\r
2906 if (MenuOption != NULL) {\r
2907 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2908 Selection = NULL;\r
2909 Repaint = TRUE;\r
2910 break;\r
2911 }\r
2912 }\r
2913 //\r
2914 // If callbacks are active, and the callback has a Write method, try to use it\r
2915 //\r
2916 if (FileFormTags->VariableDefinitions->VariableName == NULL) {\r
2917 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2918 Status = FormCallback->NvWrite (\r
2919 FormCallback,\r
2920 (CHAR16 *) L"Setup",\r
2921 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2922 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2923 VariableDefinition->VariableSize,\r
2924 (VOID *) VariableDefinition->NvRamMap,\r
2925 &gResetRequired\r
2926 );\r
2927\r
2928 } else {\r
2929 Status = gRT->SetVariable (\r
2930 (CHAR16 *) L"Setup",\r
2931 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2932 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2933 VariableDefinition->VariableSize,\r
2934 (VOID *) VariableDefinition->NvRamMap\r
2935 );\r
2936 }\r
2937 } else {\r
2938 VariableDefinition = FileFormTags->VariableDefinitions;\r
2939\r
2940 for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {\r
2941 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2942 Status = FormCallback->NvWrite (\r
2943 FormCallback,\r
2944 VariableDefinition->VariableName,\r
2945 &VariableDefinition->Guid,\r
2946 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2947 VariableDefinition->VariableSize,\r
2948 (VOID *) VariableDefinition->NvRamMap,\r
2949 &gResetRequired\r
2950 );\r
2951\r
2952 } else {\r
2953 Status = gRT->SetVariable (\r
2954 VariableDefinition->VariableName,\r
2955 &VariableDefinition->Guid,\r
2956 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2957 VariableDefinition->VariableSize,\r
2958 (VOID *) VariableDefinition->NvRamMap\r
2959 );\r
2960 }\r
2961 }\r
2962 }\r
2963\r
2964 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2965 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2966 break;\r
2967\r
2968 case CfUiDefault:\r
2969 ControlFlag = CfCheckSelection;\r
2970\r
2971 NvMapListHead = NULL;\r
2972\r
f79314fa 2973 Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, FRAMEWORK_EFI_IFR_FLAG_DEFAULT, &NvMapListHead);\r
103b6520 2974\r
2975 if (!EFI_ERROR (Status)) {\r
2976 ASSERT_EFI_ERROR (NULL != NvMapListHead);\r
2977\r
2978 NvMapListNode = NvMapListHead;\r
2979\r
2980 while (NULL != NvMapListNode) {\r
c3e02ca5 2981 \r
2982 for (UiDefaultVarDef = FileFormTags->VariableDefinitions;\r
2983 UiDefaultVarDef != NULL; \r
2984 UiDefaultVarDef = UiDefaultVarDef->Next ) {\r
2985 \r
2986 if (UiDefaultVarDef->VariableId == NvMapListNode->VariablePack->VariableId) {\r
2987 NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);\r
2988 NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;\r
2989 //\r
2990 // Free the buffer that was allocated.\r
2991 //\r
2992 FreePool (UiDefaultVarDef->NvRamMap);\r
2993 FreePool (UiDefaultVarDef->FakeNvRamMap);\r
2994 \r
2995 //\r
2996 // Allocate, copy the NvRamMap.\r
2997 //\r
2998 UiDefaultVarDef->VariableFakeSize = (UINT16) (UiDefaultVarDef->VariableFakeSize - UiDefaultVarDef->VariableSize);\r
2999 UiDefaultVarDef->VariableSize = (UINT16) NvMapSize;\r
3000 UiDefaultVarDef->VariableFakeSize = (UINT16) (UiDefaultVarDef->VariableFakeSize + UiDefaultVarDef->VariableSize);\r
3001 \r
3002 UiDefaultVarDef->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);\r
3003 ASSERT (UiDefaultVarDef->NvRamMap != NULL);\r
3004 \r
3005 UiDefaultVarDef->FakeNvRamMap = AllocateZeroPool (NvMapSize + UiDefaultVarDef->VariableFakeSize);\r
3006 ASSERT (UiDefaultVarDef->FakeNvRamMap != NULL);\r
3007 \r
3008 CopyMem (UiDefaultVarDef->NvRamMap, NvMap, NvMapSize);\r
3009 break;\r
103b6520 3010 }\r
c3e02ca5 3011 }\r
103b6520 3012 NvMapListNode = NvMapListNode->NextVariablePack;\r
3013 }\r
3014\r
103b6520 3015 FreePool (NvMapListHead);\r
3016 }\r
3017\r
3018 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);\r
3019 Repaint = TRUE;\r
3020 //\r
3021 // After the repaint operation, we should refresh the highlight.\r
3022 //\r
d4ff9b44 3023 NewLine = TRUE;\r
103b6520 3024 break;\r
3025\r
3026 case CfUiNoOperation:\r
3027 ControlFlag = CfCheckSelection;\r
3028 break;\r
3029\r
3030 case CfExit:\r
3031 while (gMenuRefreshHead != NULL) {\r
3032 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
3033\r
3034 FreePool (gMenuRefreshHead);\r
3035\r
3036 gMenuRefreshHead = OldMenuRefreshEntry;\r
3037 }\r
3038\r
3039 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3040 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3041 gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");\r
3042\r
3043 gActiveIfr = MenuOption->IfrNumber;\r
3044 return Selection;\r
3045\r
3046 default:\r
3047 break;\r
3048 }\r
3049 }\r
3050}\r
3051\r
3052BOOLEAN\r
3053ValueIsScroll (\r
3054 IN BOOLEAN Direction,\r
3055 IN LIST_ENTRY *CurrentPos\r
3056 )\r
3057/*++\r
3058\r
3059Routine Description:\r
3060 Determine if the menu is the last menu that can be selected.\r
3061\r
3062Arguments:\r
3063 Direction - the scroll direction. False is down. True is up.\r
3064\r
3065Returns:\r
3066 FALSE -- the menu isn't the last menu that can be selected.\r
3067 TRUE -- the menu is the last menu that can be selected.\r
3068--*/\r
3069{\r
3070 LIST_ENTRY *Temp;\r
3071 UI_MENU_OPTION *MenuOption;\r
3072 MenuOption = NULL;\r
3073\r
3074 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
3075\r
3076 if (Temp == &Menu) {\r
3077 return TRUE;\r
3078 }\r
3079\r
3080 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
3081 MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
f79314fa 3082 if (!(MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {\r
103b6520 3083 return FALSE;\r
3084 }\r
3085 }\r
3086\r
3087 return TRUE;\r
3088}\r
3089\r
3090UINTN\r
3091AdjustDateAndTimePosition (\r
3092 IN BOOLEAN DirectionUp,\r
3093 IN LIST_ENTRY **CurrentPosition\r
3094 )\r
3095/*++\r
3096Routine Description:\r
3097 Adjust Data and Time tag position accordingly.\r
3098 Data format : [01/02/2004] [11:22:33]\r
3099 Line number : 0 0 1 0 0 1\r
3100\r
3101Arguments:\r
3102 Direction - the up or down direction. False is down. True is up.\r
3103 CurrentPos - Current position.\r
3104\r
3105Returns:\r
3106 Return line number to pad. It is possible that we stand on a zero-advance\r
3107 data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
3108--*/\r
3109{\r
3110 UINTN Count;\r
3111 LIST_ENTRY *NewPosition;\r
3112 UI_MENU_OPTION *MenuOption;\r
3113 UINTN PadLineNumber;\r
3114\r
3115 PadLineNumber = 0;\r
3116 NewPosition = *CurrentPosition;\r
3117 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3118\r
f79314fa 3119 if ((MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == FRAMEWORK_EFI_IFR_TIME_OP)) {\r
103b6520 3120 //\r
3121 // Calculate the distance from current position to the last Date/Time op-code.\r
3122 //\r
3123 Count = 0;\r
3124 while (MenuOption->ThisTag->NumberOfLines == 0) {\r
3125 Count++;\r
3126 NewPosition = NewPosition->ForwardLink;\r
3127 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3128 PadLineNumber = 1;\r
3129 }\r
3130\r
3131 NewPosition = *CurrentPosition;\r
3132 if (DirectionUp) {\r
3133 //\r
3134 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
3135 // to be one that back to the previous set of op-codes, we need to advance to the first\r
3136 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate\r
3137 // checking can be done.\r
3138 //\r
3139 while (Count++ < 2) {\r
3140 NewPosition = NewPosition->BackLink;\r
3141 }\r
3142 } else {\r
3143 //\r
3144 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3145 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3146 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate\r
3147 // checking can be done.\r
3148 //\r
3149 while (Count-- > 0) {\r
3150 NewPosition = NewPosition->ForwardLink;\r
3151 }\r
3152 }\r
3153\r
3154 *CurrentPosition = NewPosition;\r
3155 }\r
3156\r
3157 return PadLineNumber;\r
3158}\r