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