]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[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
1cc8ee78 214STATIC\r
878ddf1f 215VOID\r
216UpdateDateAndTime (\r
217 VOID\r
218 )\r
219/*++\r
220\r
221Routine Description:\r
222 Refresh screen with current date and/or time based on screen context\r
223\r
224Arguments:\r
225 \r
226Returns:\r
227\r
228--*/\r
229{\r
230 CHAR16 *OptionString;\r
231 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
232 UINTN Index;\r
233 UINTN Loop;\r
234\r
235 OptionString = NULL;\r
236\r
237 if (gMenuRefreshHead != NULL) {\r
238\r
239 MenuRefreshEntry = gMenuRefreshHead;\r
240\r
241 do {\r
242 gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
243 ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &OptionString);\r
244\r
245 if (OptionString != NULL) {\r
246 //\r
247 // If leading spaces on OptionString - remove the spaces\r
248 //\r
249 for (Index = 0; OptionString[Index] == L' '; Index++)\r
250 ;\r
251\r
252 for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
253 OptionString[Loop] = OptionString[Index];\r
254 Loop++;\r
255 }\r
256\r
257 OptionString[Loop] = CHAR_NULL;\r
258\r
259 PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
260 }\r
261\r
262 MenuRefreshEntry = MenuRefreshEntry->Next;\r
263\r
264 } while (MenuRefreshEntry != NULL);\r
265 }\r
266\r
267 if (OptionString != NULL) {\r
268 gBS->FreePool (OptionString);\r
269 }\r
270}\r
271\r
272EFI_STATUS\r
273UiWaitForSingleEvent (\r
274 IN EFI_EVENT Event,\r
275 IN UINT64 Timeout OPTIONAL\r
276 )\r
277/*++\r
278\r
279Routine Description:\r
280 Wait for a given event to fire, or for an optional timeout to expire.\r
281\r
282Arguments:\r
283 Event - The event to wait for\r
284\r
285 Timeout - An optional timeout value in 100 ns units.\r
286\r
287Returns:\r
288\r
289 EFI_SUCCESS - Event fired before Timeout expired.\r
290 EFI_TIME_OUT - Timout expired before Event fired.\r
291\r
292--*/\r
293{\r
294 EFI_STATUS Status;\r
295 UINTN Index;\r
296 EFI_EVENT TimerEvent;\r
297 EFI_EVENT WaitList[2];\r
298\r
299 if (Timeout) {\r
300 //\r
301 // Create a timer event\r
302 //\r
303 Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);\r
304 if (!EFI_ERROR (Status)) {\r
305 //\r
306 // Set the timer event\r
307 //\r
308 gBS->SetTimer (\r
309 TimerEvent,\r
310 TimerRelative,\r
311 Timeout\r
312 );\r
313\r
314 //\r
315 // Wait for the original event or the timer\r
316 //\r
317 WaitList[0] = Event;\r
318 WaitList[1] = TimerEvent;\r
319 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
320 gBS->CloseEvent (TimerEvent);\r
321\r
322 //\r
323 // If the timer expired, change the return to timed out\r
324 //\r
325 if (!EFI_ERROR (Status) && Index == 1) {\r
326 Status = EFI_TIMEOUT;\r
327 }\r
328 }\r
329 } else {\r
330 //\r
331 // Update screen every second\r
332 //\r
333 Timeout = ONE_SECOND;\r
334\r
335 do {\r
336 Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);\r
337\r
338 //\r
339 // Set the timer event\r
340 //\r
341 gBS->SetTimer (\r
342 TimerEvent,\r
343 TimerRelative,\r
344 Timeout\r
345 );\r
346\r
347 //\r
348 // Wait for the original event or the timer\r
349 //\r
350 WaitList[0] = Event;\r
351 WaitList[1] = TimerEvent;\r
352 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
353\r
354 //\r
355 // If the timer expired, update anything that needs a refresh and keep waiting\r
356 //\r
357 if (!EFI_ERROR (Status) && Index == 1) {\r
358 Status = EFI_TIMEOUT;\r
359 UpdateDateAndTime ();\r
360 }\r
361\r
362 gBS->CloseEvent (TimerEvent);\r
363 } while (Status == EFI_TIMEOUT);\r
364 }\r
365\r
366 return Status;\r
367}\r
368\r
369VOID\r
370UiAddMenuOption (\r
371 IN CHAR16 *String,\r
372 IN EFI_HII_HANDLE Handle,\r
373 IN EFI_TAG *Tags,\r
374 IN VOID *FormBinary,\r
375 IN UINTN IfrNumber\r
376 )\r
377/*++\r
378\r
379Routine Description:\r
380 Add one menu option by specified description and context.\r
381\r
382Arguments:\r
383 String - String description for this option.\r
384 Context - Context data for entry.\r
385 \r
386Returns:\r
387\r
388--*/\r
389{\r
390 UI_MENU_OPTION *MenuOption;\r
391\r
392 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
393 ASSERT (MenuOption);\r
394\r
395 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
396 MenuOption->Description = String;\r
397 MenuOption->Handle = Handle;\r
398 MenuOption->FormBinary = FormBinary;\r
399 MenuOption->IfrNumber = IfrNumber;\r
400 MenuOption->Skip = 1;\r
401 MenuOption->Tags = Tags;\r
402 MenuOption->TagIndex = 0;\r
403 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);\r
404 MenuOption->EntryNumber = (UINT16) IfrNumber;\r
405\r
406 InsertTailList (&Menu, &MenuOption->Link);\r
407}\r
408\r
409VOID\r
410UiAddSubMenuOption (\r
411 IN CHAR16 *String,\r
412 IN EFI_HII_HANDLE Handle,\r
413 IN EFI_TAG *Tags,\r
414 IN UINTN TagIndex,\r
415 IN UINT16 FormId,\r
416 IN UINT16 MenuItemCount\r
417 )\r
418/*++\r
419\r
420Routine Description:\r
421 Add one menu option by specified description and context.\r
422\r
423Arguments:\r
424 String - String description for this option.\r
425 Context - Context data for entry.\r
426 \r
427Returns:\r
428\r
429--*/\r
430{\r
431 UI_MENU_OPTION *MenuOption;\r
432\r
433 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
434 ASSERT (MenuOption);\r
435\r
436 MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;\r
437 MenuOption->Description = String;\r
438 MenuOption->Handle = Handle;\r
439 MenuOption->Skip = Tags[TagIndex].NumberOfLines;\r
440 MenuOption->IfrNumber = gActiveIfr;\r
441 MenuOption->Tags = Tags;\r
442 MenuOption->TagIndex = TagIndex;\r
443 MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]);\r
444 MenuOption->Consistency = Tags[TagIndex].Consistency;\r
445 MenuOption->FormId = FormId;\r
446 MenuOption->GrayOut = Tags[TagIndex].GrayOut;\r
447 MenuOption->EntryNumber = MenuItemCount;\r
448\r
449 InsertTailList (&Menu, &MenuOption->Link);\r
450}\r
451\r
452EFI_STATUS\r
453CreateDialog (\r
454 IN UINTN NumberOfLines,\r
455 IN BOOLEAN HotKey,\r
456 IN UINTN MaximumStringSize,\r
457 OUT CHAR16 *StringBuffer,\r
458 OUT EFI_INPUT_KEY *KeyValue,\r
459 IN CHAR16 *String,\r
460 ...\r
461 )\r
462/*++\r
463\r
464Routine Description:\r
465 Routine used to abstract a generic dialog interface and return the selected key or string\r
466\r
467Arguments:\r
468 NumberOfLines - The number of lines for the dialog box\r
469 HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue \r
470 or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and\r
471 an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns\r
472 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
473 StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE\r
474 KeyValue - The EFI_KEY value returned if HotKey is TRUE..\r
475 String - Pointer to the first string in the list\r
476 ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box\r
477 \r
478Returns:\r
479 EFI_SUCCESS - Displayed dialog and received user interaction\r
480 EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))\r
481 EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine\r
482\r
483--*/\r
484{\r
485 VA_LIST Marker;\r
486 UINTN Count;\r
487 EFI_INPUT_KEY Key;\r
488 UINTN LargestString;\r
489 CHAR16 *TempString;\r
490 CHAR16 *BufferedString;\r
491 CHAR16 *StackString;\r
492 CHAR16 KeyPad[2];\r
493 UINTN Start;\r
494 UINTN Top;\r
495 UINTN Index;\r
878ddf1f 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
1cc8ee78 573 WaitForKeyStroke (&Key);\r
878ddf1f 574 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
575\r
576 } else {\r
577 do {\r
1cc8ee78 578 WaitForKeyStroke (&Key);\r
878ddf1f 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
1cc8ee78 1049STATIC\r
878ddf1f 1050BOOLEAN\r
1051SelectionsAreValid (\r
1052 IN UI_MENU_OPTION *MenuOption,\r
1053 IN EFI_FILE_FORM_TAGS *FileFormTagsHead\r
1054 )\r
1055/*++\r
1056\r
1057Routine Description:\r
1058 Initiate late consistency checks against the current page. \r
1059\r
1060Arguments:\r
1061 None\r
1062 \r
1063Returns:\r
1064\r
1065--*/\r
1066{\r
1067 LIST_ENTRY *Link;\r
1068 EFI_TAG *Tag;\r
1069 EFI_FILE_FORM_TAGS *FileFormTags;\r
1070 CHAR16 *StringPtr;\r
1071 CHAR16 NullCharacter;\r
878ddf1f 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
1cc8ee78 1106 WaitForKeyStroke (&Key);\r
878ddf1f 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
1cc8ee78 1287STATIC\r
878ddf1f 1288VOID\r
1289UpdateOptionSkipLines (\r
1290 IN EFI_IFR_DATA_ARRAY *PageData,\r
1291 IN UI_MENU_OPTION *MenuOption,\r
1292 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
1293 IN CHAR16 **OptionalString,\r
1294 IN UINTN SkipValue\r
1295 )\r
1296{\r
1297 UINTN Index;\r
1298 UINTN Loop;\r
1299 UINT16 Width;\r
1300 UINTN Row;\r
1301 UINTN OriginalRow;\r
1302 CHAR16 *OutputString;\r
1303 CHAR16 *OptionString;\r
1304\r
1305 Row = 0;\r
1306 OptionString = *OptionalString;\r
1307 OutputString = NULL;\r
1308\r
1309 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1310\r
1311 if (OptionString != NULL) {\r
1312 //\r
1313 // If leading spaces on OptionString - remove the spaces\r
1314 //\r
1315 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1316 ;\r
1317\r
1318 for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1319 OptionString[Loop] = OptionString[Index];\r
1320 Loop++;\r
1321 }\r
1322\r
1323 OptionString[Loop] = CHAR_NULL;\r
1324\r
1325 Width = (UINT16) gOptionBlockWidth;\r
1326\r
1327 OriginalRow = Row;\r
1328\r
1329 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1330 //\r
1331 // If there is more string to process print on the next row and increment the Skip value\r
1332 //\r
1333 if (StrLen (&OptionString[Index])) {\r
1334 if (SkipValue == 0) {\r
1335 Row++;\r
1336 //\r
1337 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1338 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1339 // some testing to ensure we are keeping this in-sync.\r
1340 //\r
1341 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1342 //\r
1343 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1344 MenuOption->Skip++;\r
1345 }\r
1346 }\r
1347 }\r
1348\r
1349 gBS->FreePool (OutputString);\r
1350 if (SkipValue != 0) {\r
1351 SkipValue--;\r
1352 }\r
1353 }\r
1354\r
1355 Row = OriginalRow;\r
1356 }\r
1357\r
1358 *OptionalString = OptionString;\r
1359}\r
1360//\r
1361// Search table for UiDisplayMenu()\r
1362//\r
1363SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {\r
1364 { SCAN_UP, UiUp },\r
1365 { SCAN_DOWN, UiDown },\r
1366 { SCAN_PAGE_UP, UiPageUp },\r
1367 { SCAN_PAGE_DOWN, UiPageDown},\r
1368 { SCAN_ESC, UiReset},\r
1369 { SCAN_F2, UiPrevious},\r
1370 { SCAN_LEFT, UiLeft },\r
1371 { SCAN_RIGHT, UiRight },\r
1372 { SCAN_F9, UiDefault},\r
1373 { SCAN_F10, UiSave }\r
1374};\r
1375\r
1376SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {\r
1377 { UiNoOperation, CfUiNoOperation },\r
1378 { UiDefault, CfUiDefault },\r
1379 { UiSelect, CfUiSelect },\r
1380 { UiUp, CfUiUp},\r
1381 { UiDown, CfUiDown },\r
1382 { UiLeft, CfUiLeft },\r
1383 { UiRight, CfUiRight },\r
1384 { UiReset, CfUiReset },\r
1385 { UiSave, CfUiSave },\r
1386 { UiPrevious, CfUiPrevious },\r
1387 { UiPageUp, CfUiPageUp },\r
1388 { UiPageDown, CfUiPageDown }\r
1389};\r
1390\r
1391UI_MENU_OPTION *\r
1392UiDisplayMenu (\r
1393 IN BOOLEAN SubMenu,\r
1394 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
1395 OUT EFI_IFR_DATA_ARRAY *PageData\r
1396 )\r
1397/*++\r
1398\r
1399Routine Description:\r
1400 Display menu and wait for user to select one menu option, then return it.\r
1401 If AutoBoot is enabled, then if user doesn't select any option,\r
1402 after period of time, it will automatically return the first menu option.\r
1403\r
1404Arguments:\r
1405 SubMenu - Indicate is sub menu.\r
1406 FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.\r
1407 PageData - A pointer to the EFI_IFR_DATA_ARRAY.\r
1408 \r
1409Returns:\r
1410 Return the pointer of the menu which selected, \r
1411 otherwise return NULL.\r
1412\r
1413--*/\r
1414{\r
1415 INTN SkipValue;\r
1416 INTN Difference;\r
1417 INTN OldSkipValue;\r
1418 UINTN Row;\r
1419 UINTN Col;\r
1420 UINTN Temp;\r
1421 UINTN Temp2;\r
1422 UINTN TopRow;\r
1423 UINTN BottomRow;\r
1424 UINTN OriginalRow;\r
1425 UINTN Index;\r
1426 UINTN DataAndTimeLineNumberPad;\r
1427 UINT32 Count;\r
1428 INT16 OriginalTimeOut;\r
1429 UINT8 *Location;\r
1430 UINT16 Width;\r
1431 CHAR16 *StringPtr;\r
1432 CHAR16 *OptionString;\r
1433 CHAR16 *OutputString;\r
1434 CHAR16 *FormattedString;\r
1435 CHAR16 YesResponse;\r
1436 CHAR16 NoResponse;\r
1437 BOOLEAN NewLine;\r
1438 BOOLEAN Repaint;\r
1439 BOOLEAN SavedValue;\r
1440 EFI_STATUS Status;\r
1441 UI_MENU_LIST *UiMenuList;\r
1442 EFI_INPUT_KEY Key;\r
1443 LIST_ENTRY *Link;\r
1444 LIST_ENTRY *NewPos;\r
1445 LIST_ENTRY *TopOfScreen;\r
1446 LIST_ENTRY *SavedListEntry;\r
1447 UI_MENU_OPTION *Selection;\r
1448 UI_MENU_OPTION *MenuOption;\r
1449 UI_MENU_OPTION *NextMenuOption;\r
1450 UI_MENU_OPTION *SavedMenuOption;\r
1451 UI_MENU_OPTION *PreviousMenuOption;\r
1452 EFI_IFR_BINARY *IfrBinary;\r
1453 UI_CONTROL_FLAG ControlFlag;\r
cb44bbdb 1454 EFI_SCREEN_DESCRIPTOR LocalScreen;\r
878ddf1f 1455 EFI_FILE_FORM_TAGS *FileFormTags;\r
1456 MENU_REFRESH_ENTRY *MenuRefreshEntry;\r
1457 MENU_REFRESH_ENTRY *OldMenuRefreshEntry;\r
1458 UI_SCREEN_OPERATION ScreenOperation;\r
1459 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
1460 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;\r
1461 EFI_HII_VARIABLE_PACK_LIST *NvMapListHead;\r
1462 EFI_HII_VARIABLE_PACK_LIST *NvMapListNode;\r
1463 VOID *NvMap;\r
1464 UINTN NvMapSize;\r
1465\r
1466 CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
1467\r
1468 VariableDefinition = NULL;\r
1469 Status = EFI_SUCCESS;\r
1470 FormattedString = NULL;\r
1471 OptionString = NULL;\r
1472 ScreenOperation = UiNoOperation;\r
1473 NewLine = TRUE;\r
1474 FormCallback = NULL;\r
1475 FileFormTags = NULL;\r
1476 OutputString = NULL;\r
1477 gUpArrow = FALSE;\r
1478 gDownArrow = FALSE;\r
1479 SkipValue = 0;\r
1480 OldSkipValue = 0;\r
1481 MenuRefreshEntry = gMenuRefreshHead;\r
1482 OldMenuRefreshEntry = gMenuRefreshHead;\r
1483 NextMenuOption = NULL;\r
1484 PreviousMenuOption = NULL;\r
1485 SavedMenuOption = NULL;\r
1486 IfrBinary = NULL;\r
1487 NvMap = NULL;\r
1488 NvMapSize = 0;\r
1489\r
1490 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
1491\r
1492 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
1493 TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1494 Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1495 } else {\r
1496 TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1497 Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
1498 }\r
1499\r
1500 if (SubMenu) {\r
1501 Col = LocalScreen.LeftColumn;\r
1502 } else {\r
1503 Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
1504 }\r
1505\r
1506 BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
1507\r
1508 TopOfScreen = Menu.ForwardLink;\r
1509 Repaint = TRUE;\r
1510 MenuOption = NULL;\r
1511\r
1512 //\r
1513 // Get user's selection\r
1514 //\r
1515 Selection = NULL;\r
1516 NewPos = Menu.ForwardLink;\r
1517 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
1518\r
1519 UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
1520\r
1521 ControlFlag = CfInitialization;\r
1522\r
1523 while (TRUE) {\r
1524 switch (ControlFlag) {\r
1525 case CfInitialization:\r
1526 ControlFlag = CfCheckSelection;\r
1527 if (gExitRequired) {\r
1528 ScreenOperation = UiReset;\r
1529 ControlFlag = CfScreenOperation;\r
1530 } else if (gSaveRequired) {\r
1531 ScreenOperation = UiSave;\r
1532 ControlFlag = CfScreenOperation;\r
1533 } else if (IsListEmpty (&Menu)) {\r
1534 ControlFlag = CfReadKey;\r
1535 }\r
1536 break;\r
1537\r
1538 case CfCheckSelection:\r
1539 if (Selection != NULL) {\r
1540 ControlFlag = CfExit;\r
1541 } else {\r
1542 ControlFlag = CfRepaint;\r
1543 }\r
1544\r
1545 FileFormTags = FileFormTagsHead;\r
1546 break;\r
1547\r
1548 case CfRepaint:\r
1549 ControlFlag = CfRefreshHighLight;\r
1550\r
1551 if (Repaint) {\r
1552 //\r
1553 // Display menu\r
1554 //\r
1555 SavedMenuOption = MenuOption;\r
1556 gDownArrow = FALSE;\r
1557 gUpArrow = FALSE;\r
1558 Row = TopRow;\r
1559\r
1560 Temp = SkipValue;\r
1561 Temp2 = SkipValue;\r
1562\r
1563 ClearLines (\r
1564 LocalScreen.LeftColumn,\r
1565 LocalScreen.RightColumn,\r
1566 TopRow - SCROLL_ARROW_HEIGHT,\r
1567 BottomRow + SCROLL_ARROW_HEIGHT,\r
1568 FIELD_TEXT | FIELD_BACKGROUND\r
1569 );\r
1570\r
1571 while (gMenuRefreshHead != NULL) {\r
1572 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
1573\r
1574 gBS->FreePool (gMenuRefreshHead);\r
1575\r
1576 gMenuRefreshHead = OldMenuRefreshEntry;\r
1577 }\r
1578\r
1579 for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
1580 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1581 MenuOption->Row = Row;\r
1582 OriginalRow = Row;\r
1583 MenuOption->Col = Col;\r
1584 MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
1585\r
1586 if (SubMenu) {\r
1587 if (MenuOption->ThisTag->GrayOut) {\r
1588 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1589 } else {\r
1590 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
1591 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1592 }\r
1593 }\r
1594\r
1595 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1596\r
1597 OriginalRow = Row;\r
1598\r
1599 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1600 if ((Temp == 0) && (Row <= BottomRow)) {\r
1601 PrintStringAt (Col, Row, OutputString);\r
1602 }\r
1603 //\r
1604 // If there is more string to process print on the next row and increment the Skip value\r
1605 //\r
1606 if (StrLen (&MenuOption->Description[Index])) {\r
1607 if (Temp == 0) {\r
1608 Row++;\r
1609 }\r
1610 }\r
1611\r
1612 gBS->FreePool (OutputString);\r
1613 if (Temp != 0) {\r
1614 Temp--;\r
1615 }\r
1616 }\r
1617\r
1618 Temp = 0;\r
1619\r
1620 Row = OriginalRow;\r
1621\r
1622 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1623 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1624\r
1625 if (OptionString != NULL) {\r
1626 //\r
1627 // If leading spaces on OptionString - remove the spaces\r
1628 //\r
1629 for (Index = 0; OptionString[Index] == L' '; Index++) {\r
1630 MenuOption->OptCol++;\r
1631 }\r
1632\r
1633 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1634 OptionString[Count] = OptionString[Index];\r
1635 Count++;\r
1636 }\r
1637\r
1638 OptionString[Count] = CHAR_NULL;\r
1639\r
1640 //\r
1641 // If this is a date or time op-code and is used to reflect an RTC, register the op-code\r
1642 //\r
1643 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
1644 MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) &&\r
1645 (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {\r
1646\r
1647 if (gMenuRefreshHead == NULL) {\r
1648 MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1649 ASSERT (MenuRefreshEntry != NULL);\r
1650 MenuRefreshEntry->MenuOption = MenuOption;\r
1651 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1652 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1653 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1654 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1655 gMenuRefreshHead = MenuRefreshEntry;\r
1656 } else {\r
1657 //\r
1658 // Advance to the last entry\r
1659 //\r
1660 for (MenuRefreshEntry = gMenuRefreshHead;\r
1661 MenuRefreshEntry->Next != NULL;\r
1662 MenuRefreshEntry = MenuRefreshEntry->Next\r
1663 )\r
1664 ;\r
1665 MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
1666 ASSERT (MenuRefreshEntry->Next != NULL);\r
1667 MenuRefreshEntry = MenuRefreshEntry->Next;\r
1668 MenuRefreshEntry->MenuOption = MenuOption;\r
1669 MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead;\r
1670 MenuRefreshEntry->CurrentColumn = MenuOption->OptCol;\r
1671 MenuRefreshEntry->CurrentRow = MenuOption->Row;\r
1672 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1673 }\r
1674 }\r
1675\r
1676 Width = (UINT16) gOptionBlockWidth;\r
1677\r
1678 OriginalRow = Row;\r
1679\r
1680 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1681 if ((Temp2 == 0) && (Row <= BottomRow)) {\r
1682 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1683 }\r
1684 //\r
1685 // If there is more string to process print on the next row and increment the Skip value\r
1686 //\r
1687 if (StrLen (&OptionString[Index])) {\r
1688 if (Temp2 == 0) {\r
1689 Row++;\r
1690 //\r
1691 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1692 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1693 // some testing to ensure we are keeping this in-sync.\r
1694 //\r
1695 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1696 //\r
1697 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1698 MenuOption->Skip++;\r
1699 }\r
1700 }\r
1701 }\r
1702\r
1703 gBS->FreePool (OutputString);\r
1704 if (Temp2 != 0) {\r
1705 Temp2--;\r
1706 }\r
1707 }\r
1708\r
1709 Temp2 = 0;\r
1710 Row = OriginalRow;\r
1711 }\r
1712 //\r
1713 // If this is a text op with secondary text information\r
1714 //\r
1715 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {\r
1716 StringPtr = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle);\r
1717\r
1718 Width = (UINT16) gOptionBlockWidth;\r
1719\r
1720 OriginalRow = Row;\r
1721\r
1722 for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
1723 if ((Temp == 0) && (Row <= BottomRow)) {\r
1724 PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
1725 }\r
1726 //\r
1727 // If there is more string to process print on the next row and increment the Skip value\r
1728 //\r
1729 if (StrLen (&StringPtr[Index])) {\r
1730 if (Temp2 == 0) {\r
1731 Row++;\r
1732 //\r
1733 // Since the Number of lines for this menu entry may or may not be reflected accurately\r
1734 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
1735 // some testing to ensure we are keeping this in-sync.\r
1736 //\r
1737 // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
1738 //\r
1739 if ((Row - OriginalRow) >= MenuOption->Skip) {\r
1740 MenuOption->Skip++;\r
1741 }\r
1742 }\r
1743 }\r
1744\r
1745 gBS->FreePool (OutputString);\r
1746 if (Temp2 != 0) {\r
1747 Temp2--;\r
1748 }\r
1749 }\r
1750\r
1751 Row = OriginalRow;\r
1752 gBS->FreePool (StringPtr);\r
1753 }\r
1754 } else {\r
1755 //\r
1756 // For now, assume left-justified 72 width max setup entries\r
1757 //\r
1758 PrintStringAt (Col, Row, MenuOption->Description);\r
1759 }\r
1760 //\r
1761 // Tracker 6210 - need to handle the bottom of the display\r
1762 //\r
1763 if (MenuOption->Skip > 1) {\r
1764 Row += MenuOption->Skip - SkipValue;\r
1765 SkipValue = 0;\r
1766 } else {\r
1767 Row += MenuOption->Skip;\r
1768 }\r
1769\r
1770 if (Row > BottomRow) {\r
1771 if (!ValueIsScroll (FALSE, Link)) {\r
1772 gDownArrow = TRUE;\r
1773 }\r
1774\r
1775 Row = BottomRow + 1;\r
1776 break;\r
1777 }\r
1778 }\r
1779\r
1780 if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
1781 gUpArrow = TRUE;\r
1782 }\r
1783\r
1784 if (gUpArrow) {\r
1785 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1786 PrintAt (\r
1787 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1788 TopRow - SCROLL_ARROW_HEIGHT,\r
1789 (CHAR16 *) L"%c",\r
1790 ARROW_UP\r
1791 );\r
1792 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1793 }\r
1794\r
1795 if (gDownArrow) {\r
1796 gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
1797 PrintAt (\r
1798 LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
1799 BottomRow + SCROLL_ARROW_HEIGHT,\r
1800 (CHAR16 *) L"%c",\r
1801 ARROW_DOWN\r
1802 );\r
1803 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1804 }\r
1805\r
1806 if (SavedMenuOption != NULL) {\r
1807 MenuOption = SavedMenuOption;\r
1808 }\r
1809 }\r
1810 break;\r
1811\r
1812 case CfRefreshHighLight:\r
1813 ControlFlag = CfUpdateHelpString;\r
1814 //\r
1815 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
1816 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
1817 //\r
1818 SavedValue = Repaint;\r
1819 Repaint = FALSE;\r
1820\r
1821 if (NewPos != NULL) {\r
1822 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1823 if (SubMenu) {\r
1824 if (gLastOpr && (gEntryNumber != -1)) {\r
1825 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1826 if (gEntryNumber != MenuOption->EntryNumber) {\r
1827 ScreenOperation = UiDown;\r
1828 ControlFlag = CfScreenOperation;\r
1829 break;\r
1830 } else {\r
1831 gLastOpr = FALSE;\r
1832 }\r
1833 }\r
1834\r
1835 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1836 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1837 if (OptionString != NULL) {\r
1838 //\r
1839 // If leading spaces on OptionString - remove the spaces\r
1840 //\r
1841 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1842 ;\r
1843\r
1844 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1845 OptionString[Count] = OptionString[Index];\r
1846 Count++;\r
1847 }\r
1848\r
1849 OptionString[Count] = CHAR_NULL;\r
1850\r
1851 Width = (UINT16) gOptionBlockWidth;\r
1852\r
1853 OriginalRow = MenuOption->Row;\r
1854\r
1855 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1856 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1857 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1858 }\r
1859 //\r
1860 // If there is more string to process print on the next row and increment the Skip value\r
1861 //\r
1862 if (StrLen (&OptionString[Index])) {\r
1863 MenuOption->Row++;\r
1864 }\r
1865\r
1866 gBS->FreePool (OutputString);\r
1867 }\r
1868\r
1869 MenuOption->Row = OriginalRow;\r
1870 } else {\r
1871 if (NewLine) {\r
1872 if (MenuOption->ThisTag->GrayOut) {\r
1873 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
1874 } else {\r
1875 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
1876 gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
1877 }\r
1878 }\r
1879\r
1880 OriginalRow = MenuOption->Row;\r
1881 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1882\r
1883 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1884 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1885 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1886 }\r
1887 //\r
1888 // If there is more string to process print on the next row and increment the Skip value\r
1889 //\r
1890 if (StrLen (&MenuOption->Description[Index])) {\r
1891 MenuOption->Row++;\r
1892 }\r
1893\r
1894 gBS->FreePool (OutputString);\r
1895 }\r
1896\r
1897 MenuOption->Row = OriginalRow;\r
1898 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1899 }\r
1900 }\r
1901 } else {\r
1902 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
1903 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
1904 }\r
1905\r
1906 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
1907\r
1908 if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {\r
1909 ScreenOperation = UiDown;\r
1910 ControlFlag = CfScreenOperation;\r
1911 break;\r
1912 } else {\r
1913 gPriorMenuEntry = 0;\r
1914 }\r
1915 //\r
1916 // This is only possible if we entered this page and the first menu option is\r
1917 // a "non-menu" item. In that case, force it UiDown\r
1918 //\r
1919 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
1920 //\r
1921 // If we previously hit an UP command and we are still sitting on a text operation\r
1922 // we must continue going up\r
1923 //\r
1924 if (ScreenOperation == UiUp) {\r
1925 ControlFlag = CfScreenOperation;\r
1926 break;\r
1927 } else {\r
1928 ScreenOperation = UiDown;\r
1929 ControlFlag = CfScreenOperation;\r
1930 break;\r
1931 }\r
1932 }\r
1933 //\r
1934 // Set reverse attribute\r
1935 //\r
1936 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
1937 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
1938\r
1939 //\r
1940 // Assuming that we have a refresh linked-list created, lets annotate the\r
1941 // appropriate entry that we are highlighting with its new attribute. Just prior to this\r
1942 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
1943 //\r
1944 if (gMenuRefreshHead != NULL) {\r
1945 for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
1946 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
1947 if (MenuRefreshEntry->MenuOption == MenuOption) {\r
1948 MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
1949 }\r
1950 }\r
1951 }\r
1952\r
1953 if (SubMenu) {\r
1954 ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
1955 if (OptionString != NULL) {\r
1956 //\r
1957 // If leading spaces on OptionString - remove the spaces\r
1958 //\r
1959 for (Index = 0; OptionString[Index] == L' '; Index++)\r
1960 ;\r
1961\r
1962 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
1963 OptionString[Count] = OptionString[Index];\r
1964 Count++;\r
1965 }\r
1966\r
1967 OptionString[Count] = CHAR_NULL;\r
1968\r
1969 Width = (UINT16) gOptionBlockWidth;\r
1970\r
1971 OriginalRow = MenuOption->Row;\r
1972\r
1973 for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
1974 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1975 PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
1976 }\r
1977 //\r
1978 // If there is more string to process print on the next row and increment the Skip value\r
1979 //\r
1980 if (StrLen (&OptionString[Index])) {\r
1981 MenuOption->Row++;\r
1982 }\r
1983\r
1984 gBS->FreePool (OutputString);\r
1985 }\r
1986\r
1987 MenuOption->Row = OriginalRow;\r
1988 } else {\r
1989 if (NewLine) {\r
1990 OriginalRow = MenuOption->Row;\r
1991\r
1992 Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
1993\r
1994 for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
1995 if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
1996 PrintStringAt (Col, MenuOption->Row, OutputString);\r
1997 }\r
1998 //\r
1999 // If there is more string to process print on the next row and increment the Skip value\r
2000 //\r
2001 if (StrLen (&MenuOption->Description[Index])) {\r
2002 MenuOption->Row++;\r
2003 }\r
2004\r
2005 gBS->FreePool (OutputString);\r
2006 }\r
2007\r
2008 MenuOption->Row = OriginalRow;\r
2009\r
2010 }\r
2011 }\r
2012\r
2013 if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||\r
2014 ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||\r
2015 (ScreenOperation == UiNoOperation)\r
2016 ) {\r
2017 UpdateKeyHelp (MenuOption, FALSE);\r
2018 }\r
2019 } else {\r
2020 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2021 }\r
2022 //\r
2023 // Clear reverse attribute\r
2024 //\r
2025 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
2026 }\r
2027 //\r
2028 // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
2029 // if we didn't break halfway when process CfRefreshHighLight.\r
2030 //\r
2031 Repaint = SavedValue;\r
2032 break;\r
2033\r
2034 case CfUpdateHelpString:\r
2035 ControlFlag = CfPrepareToReadKey;\r
2036\r
2037 if (SubMenu && \r
2038 (Repaint || NewLine || \r
2039 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2040 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) && \r
2041 !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
2042 //\r
2043 // Don't print anything if it is a NULL help token\r
2044 //\r
2045 if (MenuOption->ThisTag->Help == 0x00000000) {\r
2046 StringPtr = (CHAR16 *) L"\0";\r
2047 } else {\r
2048 StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
2049 }\r
2050\r
2051 ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
2052\r
2053 gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
2054\r
2055 for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
2056 //\r
2057 // Pad String with spaces to simulate a clearing of the previous line\r
2058 //\r
2059 for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth]) / 2 < gHelpBlockWidth;) {\r
2060 StrCat (&FormattedString[Index * gHelpBlockWidth], (CHAR16 *) L" ");\r
2061 }\r
2062\r
2063 PrintStringAt (\r
2064 LocalScreen.RightColumn - gHelpBlockWidth,\r
2065 Index + TopRow,\r
2066 &FormattedString[Index * gHelpBlockWidth]\r
2067 );\r
2068 }\r
2069 }\r
2070 //\r
2071 // Reset this flag every time we finish using it.\r
2072 //\r
2073 Repaint = FALSE;\r
2074 NewLine = FALSE;\r
2075 break;\r
2076\r
2077 case CfPrepareToReadKey:\r
2078 ControlFlag = CfReadKey;\r
2079\r
2080 for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
2081 FileFormTags = FileFormTags->NextFile;\r
2082 }\r
2083\r
2084 ScreenOperation = UiNoOperation;\r
2085\r
2086 Status = gBS->HandleProtocol (\r
2087 (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,\r
2088 &gEfiFormCallbackProtocolGuid,\r
2089 (VOID **) &FormCallback\r
2090 );\r
2091\r
2092 break;\r
2093\r
2094 case CfReadKey:\r
2095 ControlFlag = CfScreenOperation;\r
2096\r
2097 OriginalTimeOut = FrontPageTimeOutValue;\r
2098 do {\r
2099 if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {\r
2100 //\r
2101 // Remember that if set to 0, must immediately boot an option\r
2102 //\r
2103 if (FrontPageTimeOutValue == 0) {\r
2104 FrontPageTimeOutValue = 0xFFFF;\r
2105 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2106 if (EFI_ERROR (Status)) {\r
2107 Status = EFI_TIMEOUT;\r
2108 }\r
2109 break;\r
2110 }\r
2111\r
2112 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);\r
2113 if (Status == EFI_TIMEOUT) {\r
2114 EFI_IFR_DATA_ENTRY *DataEntry;\r
2115\r
2116 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
2117\r
2118 PageData->EntryCount = 1;\r
2119 Count = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);\r
2120 CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));\r
2121\r
2122 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2123 FormCallback->Callback (\r
2124 FormCallback,\r
2125 0xFFFF,\r
2126 (EFI_IFR_DATA_ARRAY *) PageData,\r
2127 NULL\r
2128 );\r
2129 }\r
2130 //\r
2131 // Count down 1 second\r
2132 //\r
2133 FrontPageTimeOutValue--;\r
2134\r
2135 } else {\r
2136 ASSERT (!EFI_ERROR (Status));\r
2137 PageData->EntryCount = 0;\r
2138 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
2139 FormCallback->Callback (\r
2140 FormCallback,\r
2141 0xFFFE,\r
2142 (EFI_IFR_DATA_ARRAY *) PageData,\r
2143 NULL\r
2144 );\r
2145 }\r
2146\r
2147 FrontPageTimeOutValue = 0xFFFF;\r
2148 }\r
2149 } else {\r
2150 //\r
2151 // Wait for user's selection, no auto boot\r
2152 //\r
2153 Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
2154 }\r
2155 } while (Status == EFI_TIMEOUT);\r
2156\r
2157 if (gFirstIn) {\r
2158 gFirstIn = FALSE;\r
2159 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2160 DisableQuietBoot ();\r
2161 }\r
2162\r
2163 if (Status == EFI_TIMEOUT) {\r
2164 Key.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
2165 } else {\r
2166 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2167 //\r
2168 // if we encounter error, continue to read another key in.\r
2169 //\r
2170 if (EFI_ERROR (Status)) {\r
2171 ControlFlag = CfReadKey;\r
2172 continue;\r
2173 }\r
2174 }\r
2175\r
2176 switch (Key.UnicodeChar) {\r
2177 case CHAR_CARRIAGE_RETURN:\r
2178 Selection = MenuOption;\r
2179 ScreenOperation = UiSelect;\r
2180 gDirection = 0;\r
2181 break;\r
2182\r
2183 //\r
2184 // We will push the adjustment of these numeric values directly to the input handler\r
2185 //\r
2186 case '+':\r
2187 case '-':\r
2188 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2189\r
2190 if (Key.UnicodeChar == '+') {\r
2191 gDirection = SCAN_RIGHT;\r
2192 } else {\r
2193 gDirection = SCAN_LEFT;\r
2194 }\r
2195\r
2196 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);\r
2197 }\r
2198 break;\r
2199\r
2200 case '^':\r
2201 ScreenOperation = UiUp;\r
2202 break;\r
2203\r
2204 case 'V':\r
2205 case 'v':\r
2206 ScreenOperation = UiDown;\r
2207 break;\r
2208\r
2209 case ' ':\r
2210 if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
2211 if (SubMenu) {\r
2212 if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {\r
2213 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
2214 gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
2215 Selection = MenuOption;\r
2216 ScreenOperation = UiSelect;\r
2217 }\r
2218 }\r
2219 }\r
2220 break;\r
2221\r
2222 case CHAR_NULL:\r
2223 if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
2224 ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
2225 ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
2226 ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
2227 ) {\r
2228 //\r
2229 // If the function key has been disabled, just ignore the key.\r
2230 //\r
2231 } else {\r
2232 for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
2233 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
2234 if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) {\r
2235 if (SubMenu) {\r
2236 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2237 }\r
2238 } else {\r
2239 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
2240 }\r
2241 }\r
2242 }\r
2243 }\r
2244 break;\r
2245 }\r
2246 break;\r
2247\r
2248 case CfScreenOperation:\r
2249 IfrBinary = gBinaryDataHead;\r
2250\r
2251 //\r
2252 // Advance to the Ifr we are using\r
2253 //\r
2254 for (Index = 0; Index < gActiveIfr; Index++) {\r
2255 IfrBinary = IfrBinary->Next;\r
2256 }\r
2257\r
2258 if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
2259 //\r
2260 // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
2261 // ignore the selection and go back to reading keys.\r
2262 //\r
2263 if (IsListEmpty (&Menu)) {\r
2264 ControlFlag = CfReadKey;\r
2265 break;\r
2266 }\r
2267 //\r
2268 // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
2269 //\r
2270 for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
2271 NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2272 if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) {\r
2273 break;\r
2274 }\r
2275 }\r
2276\r
2277 if (Link == &Menu) {\r
2278 ControlFlag = CfPrepareToReadKey;\r
2279 break;\r
2280 }\r
2281 }\r
2282\r
2283 for (Index = 0;\r
2284 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
2285 Index++\r
2286 ) {\r
2287 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
2288 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
2289 }\r
2290 }\r
2291\r
2292 break;\r
2293\r
2294 case CfUiPrevious:\r
2295 ControlFlag = CfCheckSelection;\r
2296 //\r
2297 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2298 //\r
2299 if (MenuOption != NULL) {\r
2300 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2301 Selection = NULL;\r
2302 Repaint = TRUE;\r
2303 break;\r
2304 }\r
2305 }\r
2306\r
2307 if (IsListEmpty (&gMenuList)) {\r
2308 Selection = NULL;\r
2309 if (IsListEmpty (&Menu)) {\r
2310 ControlFlag = CfReadKey;\r
2311 }\r
2312 break;\r
2313 }\r
2314\r
2315 gLastOpr = TRUE;\r
2316\r
2317 while (gMenuRefreshHead != NULL) {\r
2318 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
2319\r
2320 gBS->FreePool (gMenuRefreshHead);\r
2321\r
2322 gMenuRefreshHead = OldMenuRefreshEntry;\r
2323 }\r
2324 //\r
2325 // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag\r
2326 //\r
2327 if (SubMenu) {\r
2328 UiRemoveMenuListEntry (MenuOption, &Selection);\r
2329 Selection->Previous = TRUE;\r
2330 UiFreeMenu ();\r
2331 UiInitMenu ();\r
2332 }\r
2333\r
2334 gActiveIfr = Selection->IfrNumber;\r
2335 return Selection;\r
2336\r
2337 case CfUiSelect:\r
2338 ControlFlag = CfCheckSelection;\r
2339\r
2340 ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);\r
2341\r
2342 if (SubMenu) {\r
2343 if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP && \r
2344 !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) ||\r
2345 (MenuOption->ThisTag->GrayOut) ||\r
2346 (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
2347 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2348 Selection = NULL;\r
2349 break;\r
2350 }\r
2351\r
2352 NewLine = TRUE;\r
2353 UpdateKeyHelp (MenuOption, TRUE);\r
2354 Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);\r
2355\r
2356 if (EFI_ERROR (Status)) {\r
2357 Selection = NULL;\r
2358 Repaint = TRUE;\r
2359 break;\r
2360 }\r
2361\r
2362 if (OptionString != NULL) {\r
2363 PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);\r
2364 }\r
2365\r
2366 if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
2367 Selection = MenuOption;\r
2368 }\r
2369\r
2370 if (Selection == NULL) {\r
2371 break;\r
2372 }\r
2373\r
2374 Location = (UINT8 *) &PageData->EntryCount;\r
2375\r
2376 //\r
2377 // If not a goto, dump single piece of data, otherwise dump everything\r
2378 //\r
2379 if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) {\r
2380 //\r
2381 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2382 //\r
2383 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2384 Selection = NULL;\r
2385 Repaint = TRUE;\r
2386 break;\r
2387 }\r
2388\r
2389 UiAddMenuListEntry (Selection);\r
2390 gPriorMenuEntry = 0;\r
2391\r
2392 //\r
2393 // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious\r
2394 //\r
2395 UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
2396 UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;\r
2397\r
2398 gLastOpr = FALSE;\r
2399\r
2400 //\r
2401 // Rewind to the beginning of the menu\r
2402 //\r
2403 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2404 ;\r
2405\r
2406 //\r
2407 // Get Total Count of Menu entries\r
2408 //\r
2409 for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {\r
2410 Count++;\r
2411 }\r
2412 //\r
2413 // Rewind to the beginning of the menu\r
2414 //\r
2415 for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
2416 ;\r
2417\r
2418 //\r
2419 // Copy the number of entries being described to the PageData location\r
2420 //\r
2421 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2422\r
2423 for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {\r
2424\r
2425 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2426 Location[Index] = MenuOption->ThisTag->Operand;\r
2427 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2428 CopyMem (\r
2429 &Location[Index + 4],\r
2430 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2431 MenuOption->ThisTag->StorageWidth\r
2432 );\r
2433 NewPos = NewPos->ForwardLink;\r
2434 }\r
2435 } else {\r
2436\r
2437 gPriorMenuEntry = MenuOption->EntryNumber;\r
2438\r
2439 Count = 1;\r
2440\r
2441 //\r
2442 // Copy the number of entries being described to the PageData location\r
2443 //\r
2444 CopyMem (&Location[0], &Count, sizeof (UINT32));\r
2445\r
2446 //\r
2447 // Start at PageData[4] since the EntryCount is a UINT32\r
2448 //\r
2449 Index = 4;\r
2450\r
2451 //\r
2452 // Copy data to destination\r
2453 //\r
2454 Location[Index] = MenuOption->ThisTag->Operand;\r
2455 Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
2456 CopyMem (\r
2457 &Location[Index + 4],\r
2458 &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
2459 MenuOption->ThisTag->StorageWidth\r
2460 );\r
2461 }\r
2462 }\r
2463 break;\r
2464\r
2465 case CfUiReset:\r
2466 ControlFlag = CfCheckSelection;\r
2467 gLastOpr = FALSE;\r
2468 if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
2469 break;\r
2470 }\r
2471 //\r
2472 // If NV flag is up, prompt user\r
2473 //\r
2474 if (gNvUpdateRequired) {\r
2475 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
2476\r
2477 YesResponse = gYesResponse[0];\r
2478 NoResponse = gNoResponse[0];\r
2479\r
2480 do {\r
2481 CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
2482 } while\r
2483 (\r
2484 (Key.ScanCode != SCAN_ESC) &&\r
2485 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
2486 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
2487 );\r
2488\r
2489 //\r
2490 // If the user hits the YesResponse key\r
2491 //\r
2492 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
2493 } else {\r
2494 Repaint = TRUE;\r
2495 NewLine = TRUE;\r
2496 break;\r
2497 }\r
2498 }\r
2499 //\r
2500 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2501 //\r
2502 if (MenuOption != NULL) {\r
2503 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2504 Selection = NULL;\r
2505 Repaint = TRUE;\r
2506 NewLine = TRUE;\r
2507 break;\r
2508 }\r
2509 }\r
2510\r
2511 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
2512 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
2513\r
2514 if (SubMenu) {\r
2515 UiFreeMenuList ();\r
2516 gST->ConOut->ClearScreen (gST->ConOut);\r
2517 return NULL;\r
2518 }\r
2519\r
2520 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2521 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2522\r
2523 if (IfrBinary->UnRegisterOnExit) {\r
2524 Hii->RemovePack (Hii, MenuOption->Handle);\r
2525 }\r
2526\r
2527 UiFreeMenu ();\r
2528\r
2529 //\r
2530 // Clean up the allocated data buffers\r
2531 //\r
2532 FreeData (FileFormTagsHead, FormattedString, OptionString);\r
2533\r
2534 gST->ConOut->ClearScreen (gST->ConOut);\r
2535 return NULL;\r
2536\r
2537 case CfUiLeft:\r
2538 ControlFlag = CfCheckSelection;\r
2539 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
2540 if (MenuOption->Skip == 1) {\r
2541 //\r
2542 // In the tail of the Date/Time op-code set, go left.\r
2543 //\r
2544 NewPos = NewPos->BackLink;\r
2545 } else {\r
2546 //\r
2547 // In the middle of the Data/Time op-code set, go left.\r
2548 //\r
2549 NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2550 if (NextMenuOption->Skip == 1) {\r
2551 NewPos = NewPos->BackLink;\r
2552 }\r
2553 }\r
2554 }\r
2555 break;\r
2556\r
2557 case CfUiRight:\r
2558 ControlFlag = CfCheckSelection;\r
2559 if ((MenuOption->Skip == 0) &&\r
2560 ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP))\r
2561 ) {\r
2562 //\r
2563 // We are in the head or middle of the Date/Time op-code set, advance right.\r
2564 //\r
2565 NewPos = NewPos->ForwardLink;\r
2566 }\r
2567 break;\r
2568\r
2569 case CfUiUp:\r
2570 ControlFlag = CfCheckSelection;\r
2571\r
2572 if (NewPos->BackLink != &Menu) {\r
2573 NewLine = TRUE;\r
2574 //\r
2575 // Adjust Date/Time position before we advance forward.\r
2576 //\r
2577 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2578\r
2579 //\r
2580 // Caution that we have already rewind to the top, don't go backward in this situation.\r
2581 //\r
2582 if (NewPos->BackLink != &Menu) {\r
2583 NewPos = NewPos->BackLink;\r
2584 }\r
2585\r
2586 PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2587\r
2588 //\r
2589 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
2590 // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
2591 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2592 // checking can be done.\r
2593 //\r
2594 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);\r
2595\r
2596 if (SubMenu) {\r
2597 //\r
2598 // If the previous MenuOption contains a display-only op-code, skip to the next one\r
2599 //\r
2600 if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {\r
2601 //\r
2602 // This is ok as long as not at the end of the list\r
2603 //\r
2604 if (NewPos->BackLink == &Menu) {\r
2605 //\r
2606 // If we are at the start of the list, then this list must start with a display only\r
2607 // piece of data, so do not allow the backward motion\r
2608 //\r
2609 ScreenOperation = UiDown;\r
2610\r
2611 if (PreviousMenuOption->Row <= TopRow) {\r
2612 if (TopOfScreen->BackLink != &Menu) {\r
2613 TopOfScreen = TopOfScreen->BackLink;\r
2614 Repaint = TRUE;\r
2615 }\r
2616 }\r
2617\r
2618 UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);\r
2619 break;\r
2620 }\r
2621 }\r
2622 }\r
2623 //\r
2624 // Check the previous menu entry to see if it was a zero-length advance. If it was,\r
2625 // don't worry about a redraw.\r
2626 //\r
2627 if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||\r
2628 (PreviousMenuOption->Skip > MenuOption->Row)\r
2629 ) {\r
2630 do {\r
2631 if (TopOfScreen->BackLink == &Menu) {\r
2632 break;\r
2633 }\r
2634\r
2635 Repaint = TRUE;\r
2636\r
2637 //\r
2638 // Is the current top of screen a zero-advance op-code?\r
2639 // If so, keep moving forward till we hit a >0 advance op-code\r
2640 //\r
2641 SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2642 TopOfScreen = TopOfScreen->BackLink;\r
2643 } while (SavedMenuOption->Skip == 0);\r
2644 //\r
2645 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2646 //\r
2647 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2648 }\r
2649\r
2650 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2651 } else {\r
2652 if (SubMenu) {\r
2653 SavedMenuOption = MenuOption;\r
2654 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2655 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
2656 //\r
2657 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2658 //\r
2659 ScreenOperation = UiDown;\r
2660 ControlFlag = CfScreenOperation;\r
2661 break;\r
2662 }\r
2663\r
2664 MenuOption = SavedMenuOption;\r
2665 }\r
2666 }\r
2667 break;\r
2668\r
2669 case CfUiPageUp:\r
2670 ControlFlag = CfCheckSelection;\r
2671\r
2672 SavedListEntry = NewPos;\r
2673 Link = TopOfScreen;\r
2674 for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {\r
2675 if (Link->BackLink == &Menu) {\r
2676 TopOfScreen = Link;\r
2677 Link = SavedListEntry;\r
2678 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2679 break;\r
2680 }\r
2681\r
2682 NewLine = TRUE;\r
2683 Repaint = TRUE;\r
2684 Link = Link->BackLink;\r
2685 MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2686 TopOfScreen = Link;\r
2687 SavedListEntry = Link;\r
2688 }\r
2689\r
2690 NewPos = Link;\r
2691\r
2692 //\r
2693 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2694 // Don't do this when we are already in the first page.\r
2695 //\r
2696 if (Repaint) {\r
2697 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2698 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2699 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2700 }\r
2701 break;\r
2702\r
2703 case CfUiPageDown:\r
2704 ControlFlag = CfCheckSelection;\r
2705\r
2706 SavedListEntry = NewPos;\r
2707 Link = TopOfScreen;\r
2708 NewPos = TopOfScreen;\r
2709 for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {\r
2710 if (NewPos->ForwardLink == &Menu) {\r
2711 NewPos = SavedListEntry;\r
2712 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2713 Link = TopOfScreen;\r
2714 NewLine = FALSE;\r
2715 Repaint = FALSE;\r
2716 break;\r
2717 }\r
2718\r
2719 NewLine = TRUE;\r
2720 Repaint = TRUE;\r
2721 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2722 NewPos = NewPos->ForwardLink;\r
2723 Link = NewPos;\r
2724 }\r
2725\r
2726 TopOfScreen = Link;\r
2727\r
2728 //\r
2729 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
2730 // Don't do this when we are already in the last page.\r
2731 //\r
2732 if (Repaint) {\r
2733 AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
2734 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2735 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2736 }\r
2737 break;\r
2738\r
2739 case CfUiDown:\r
2740 ControlFlag = CfCheckSelection;\r
2741 //\r
2742 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
2743 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
2744 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
2745 // checking can be done. The only other logic we need to introduce is that if a Date/Time\r
2746 // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
2747 // the Date/Time op-code.\r
2748 //\r
2749 DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);\r
2750\r
2751 if (NewPos->ForwardLink != &Menu) {\r
2752 NewLine = TRUE;\r
2753 NewPos = NewPos->ForwardLink;\r
2754 NextMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2755\r
2756 if (SubMenu) {\r
2757 //\r
2758 // If the next MenuOption contains a display-only op-code, skip to the next one\r
2759 // Also if the next MenuOption is date or time,\r
2760 //\r
2761 if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {\r
2762 //\r
2763 // This is ok as long as not at the end of the list\r
2764 //\r
2765 if (NewPos == &Menu) {\r
2766 //\r
2767 // If we are at the end of the list, then this list must end with a display only\r
2768 // piece of data, so do not allow the forward motion\r
2769 //\r
2770 UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);\r
2771 NewPos = NewPos->BackLink;\r
2772 ScreenOperation = UiUp;\r
2773 break;\r
2774 }\r
2775 }\r
2776 }\r
2777 //\r
2778 // An option might be multi-line, so we need to reflect that data in the overall skip value\r
2779 //\r
2780 UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);\r
2781\r
2782 if (NextMenuOption->Skip > 1) {\r
2783 Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;\r
2784 } else {\r
2785 Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;\r
2786 }\r
2787 //\r
2788 // If we are going to scroll\r
2789 //\r
2790 if (Temp > BottomRow) {\r
2791 do {\r
2792 //\r
2793 // Is the current top of screen a zero-advance op-code?\r
2794 // If so, keep moving forward till we hit a >0 advance op-code\r
2795 //\r
2796 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2797\r
2798 //\r
2799 // If bottom op-code is more than one line or top op-code is more than one line\r
2800 //\r
2801 if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) {\r
2802 //\r
2803 // Is the bottom op-code greater than or equal in size to the top op-code?\r
2804 //\r
2805 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
2806 //\r
2807 // Skip the top op-code\r
2808 //\r
2809 TopOfScreen = TopOfScreen->ForwardLink;\r
2810 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
2811\r
2812 OldSkipValue = Difference;\r
2813\r
2814 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2815\r
2816 //\r
2817 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
2818 //\r
2819 for (;\r
2820 Difference >= (INTN) SavedMenuOption->Skip;\r
2821 Difference = Difference - (INTN) SavedMenuOption->Skip\r
2822 ) {\r
2823 //\r
2824 // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
2825 //\r
2826 TopOfScreen = TopOfScreen->ForwardLink;\r
2827 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2828 if (Difference < (INTN) SavedMenuOption->Skip) {\r
2829 Difference = SavedMenuOption->Skip - Difference - 1;\r
2830 break;\r
2831 } else {\r
2832 if (Difference == (INTN) SavedMenuOption->Skip) {\r
2833 TopOfScreen = TopOfScreen->ForwardLink;\r
2834 SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2835 Difference = SavedMenuOption->Skip - Difference;\r
2836 break;\r
2837 }\r
2838 }\r
2839 }\r
2840 //\r
2841 // Since we will act on this op-code in the next routine, and increment the\r
2842 // SkipValue, set the skips to one less than what is required.\r
2843 //\r
2844 SkipValue = Difference - 1;\r
2845\r
2846 } else {\r
2847 //\r
2848 // Since we will act on this op-code in the next routine, and increment the\r
2849 // SkipValue, set the skips to one less than what is required.\r
2850 //\r
2851 SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
2852 }\r
2853 } else {\r
2854 if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
2855 TopOfScreen = TopOfScreen->ForwardLink;\r
2856 break;\r
2857 } else {\r
2858 SkipValue = OldSkipValue;\r
2859 }\r
2860 }\r
2861 //\r
2862 // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
2863 // Let's set a skip flag to smoothly scroll the top of the screen.\r
2864 //\r
2865 if (SavedMenuOption->Skip > 1) {\r
2866 if (SavedMenuOption == NextMenuOption) {\r
2867 SkipValue = 0;\r
2868 } else {\r
2869 SkipValue++;\r
2870 }\r
2871 } else {\r
2872 SkipValue = 0;\r
2873 TopOfScreen = TopOfScreen->ForwardLink;\r
2874 }\r
2875 } while (SavedMenuOption->Skip == 0);\r
2876\r
2877 Repaint = TRUE;\r
2878 OldSkipValue = SkipValue;\r
2879 }\r
2880\r
2881 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2882\r
2883 } else {\r
2884 if (SubMenu) {\r
2885 SavedMenuOption = MenuOption;\r
2886 MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
2887 if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
2888 //\r
2889 // If we are at the end of the list and sitting on a text op, we need to more forward\r
2890 //\r
2891 ScreenOperation = UiUp;\r
2892 ControlFlag = CfScreenOperation;\r
2893 break;\r
2894 }\r
2895\r
2896 MenuOption = SavedMenuOption;\r
2897 //\r
2898 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
2899 //\r
2900 AdjustDateAndTimePosition (TRUE, &NewPos);\r
2901 }\r
2902 }\r
2903 break;\r
2904\r
2905 case CfUiSave:\r
2906 ControlFlag = CfCheckSelection;\r
2907 //\r
2908 // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data.\r
2909 //\r
2910 if (MenuOption != NULL) {\r
2911 if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
2912 Selection = NULL;\r
2913 Repaint = TRUE;\r
2914 break;\r
2915 }\r
2916 }\r
2917 //\r
2918 // If callbacks are active, and the callback has a Write method, try to use it\r
2919 //\r
2920 if (FileFormTags->VariableDefinitions->VariableName == NULL) {\r
2921 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2922 Status = FormCallback->NvWrite (\r
2923 FormCallback,\r
2924 (CHAR16 *) L"Setup",\r
2925 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2926 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2927 VariableDefinition->VariableSize,\r
2928 (VOID *) VariableDefinition->NvRamMap,\r
2929 &gResetRequired\r
2930 );\r
2931\r
2932 } else {\r
2933 Status = gRT->SetVariable (\r
2934 (CHAR16 *) L"Setup",\r
2935 &FileFormTags->FormTags.Tags[0].GuidValue,\r
2936 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2937 VariableDefinition->VariableSize,\r
2938 (VOID *) VariableDefinition->NvRamMap\r
2939 );\r
2940 }\r
2941 } else {\r
2942 VariableDefinition = FileFormTags->VariableDefinitions;\r
2943\r
2944 for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {\r
2945 if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
2946 Status = FormCallback->NvWrite (\r
2947 FormCallback,\r
2948 VariableDefinition->VariableName,\r
2949 &VariableDefinition->Guid,\r
2950 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2951 VariableDefinition->VariableSize,\r
2952 (VOID *) VariableDefinition->NvRamMap,\r
2953 &gResetRequired\r
2954 );\r
2955\r
2956 } else {\r
2957 Status = gRT->SetVariable (\r
2958 VariableDefinition->VariableName,\r
2959 &VariableDefinition->Guid,\r
2960 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2961 VariableDefinition->VariableSize,\r
2962 (VOID *) VariableDefinition->NvRamMap\r
2963 );\r
2964 }\r
2965 }\r
2966 }\r
2967\r
2968 UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
2969 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
2970 break;\r
2971\r
2972 case CfUiDefault:\r
2973 ControlFlag = CfCheckSelection;\r
2974\r
2975 NvMapListHead = NULL;\r
2976\r
2977 Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead);\r
2978\r
2979 if (!EFI_ERROR (Status)) {\r
2980 ASSERT_EFI_ERROR (NULL != NvMapListHead);\r
2981 \r
2982 NvMapListNode = NvMapListHead;\r
2983 \r
2984 while (NULL != NvMapListNode) {\r
2985 if (FileFormTags->VariableDefinitions->VariableId == NvMapListNode->VariablePack->VariableId) {\r
2986 NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);\r
2987 NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;\r
2988 break;\r
2989 }\r
2990 NvMapListNode = NvMapListNode->NextVariablePack;\r
2991 }\r
2992 \r
2993 //\r
2994 // Free the buffer that was allocated.\r
2995 //\r
2996 gBS->FreePool (FileFormTags->VariableDefinitions->NvRamMap);\r
2997 gBS->FreePool (FileFormTags->VariableDefinitions->FakeNvRamMap);\r
2998 \r
2999 //\r
3000 // Allocate, copy the NvRamMap.\r
3001 //\r
3002 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize - FileFormTags->VariableDefinitions->VariableSize);\r
3003 FileFormTags->VariableDefinitions->VariableSize = (UINT16) NvMapSize;\r
3004 FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize + FileFormTags->VariableDefinitions->VariableSize);\r
3005 \r
3006 FileFormTags->VariableDefinitions->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);\r
41a907e4 3007 ASSERT (FileFormTags->VariableDefinitions->NvRamMap != NULL);\r
3008\r
878ddf1f 3009 FileFormTags->VariableDefinitions->FakeNvRamMap = AllocateZeroPool (NvMapSize + FileFormTags->VariableDefinitions->VariableFakeSize);\r
41a907e4 3010 ASSERT (FileFormTags->VariableDefinitions->FakeNvRamMap != NULL);\r
878ddf1f 3011\r
3012 CopyMem (FileFormTags->VariableDefinitions->NvRamMap, NvMap, NvMapSize);\r
3013 gBS->FreePool (NvMapListHead);\r
3014 }\r
3015\r
3016 UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);\r
3017 Repaint = TRUE;\r
3018 //\r
3019 // After the repaint operation, we should refresh the highlight.\r
3020 //\r
3021 NewLine = TRUE;\r
3022 break;\r
3023\r
3024 case CfUiNoOperation:\r
3025 ControlFlag = CfCheckSelection;\r
3026 break;\r
3027\r
3028 case CfExit:\r
3029 while (gMenuRefreshHead != NULL) {\r
3030 OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
3031\r
3032 gBS->FreePool (gMenuRefreshHead);\r
3033\r
3034 gMenuRefreshHead = OldMenuRefreshEntry;\r
3035 }\r
3036\r
3037 gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
3038 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
3039 gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");\r
3040\r
3041 gActiveIfr = MenuOption->IfrNumber;\r
3042 return Selection;\r
3043\r
3044 default:\r
3045 break;\r
3046 }\r
3047 }\r
3048}\r
3049\r
3050BOOLEAN\r
3051ValueIsScroll (\r
3052 IN BOOLEAN Direction,\r
3053 IN LIST_ENTRY *CurrentPos\r
3054 )\r
3055/*++\r
3056\r
3057Routine Description:\r
3058 Determine if the menu is the last menu that can be selected. \r
3059\r
3060Arguments:\r
3061 Direction - the scroll direction. False is down. True is up.\r
3062 \r
3063Returns:\r
3064 FALSE -- the menu isn't the last menu that can be selected.\r
3065 TRUE -- the menu is the last menu that can be selected.\r
3066--*/\r
3067{\r
3068 LIST_ENTRY *Temp;\r
3069 UI_MENU_OPTION *MenuOption;\r
3070 MenuOption = NULL;\r
3071\r
3072 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
3073\r
3074 if (Temp == &Menu) {\r
3075 return TRUE;\r
3076 }\r
3077\r
3078 for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
3079 MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3080 if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {\r
3081 return FALSE;\r
3082 }\r
3083 }\r
3084\r
3085 return TRUE;\r
3086}\r
3087\r
3088UINTN\r
3089AdjustDateAndTimePosition (\r
3090 IN BOOLEAN DirectionUp,\r
3091 IN LIST_ENTRY **CurrentPosition\r
3092 )\r
3093/*++\r
3094Routine Description:\r
3095 Adjust Data and Time tag position accordingly.\r
3096 Data format : [01/02/2004] [11:22:33]\r
3097 Line number : 0 0 1 0 0 1\r
3098\r
3099Arguments:\r
3100 Direction - the up or down direction. False is down. True is up.\r
3101 CurrentPos - Current position.\r
3102 \r
3103Returns:\r
3104 Return line number to pad. It is possible that we stand on a zero-advance \r
3105 data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
3106--*/\r
3107{\r
3108 UINTN Count;\r
3109 LIST_ENTRY *NewPosition;\r
3110 UI_MENU_OPTION *MenuOption;\r
3111 UINTN PadLineNumber;\r
3112\r
3113 PadLineNumber = 0;\r
3114 NewPosition = *CurrentPosition;\r
3115 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3116\r
3117 if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
3118 //\r
3119 // Calculate the distance from current position to the last Date/Time op-code.\r
3120 //\r
3121 Count = 0;\r
3122 while (MenuOption->ThisTag->NumberOfLines == 0) {\r
3123 Count++;\r
3124 NewPosition = NewPosition->ForwardLink;\r
3125 MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
3126 PadLineNumber = 1;\r
3127 }\r
3128\r
3129 NewPosition = *CurrentPosition;\r
3130 if (DirectionUp) {\r
3131 //\r
3132 // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
3133 // to be one that back to the previous set of op-codes, we need to advance to the first\r
3134 // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate\r
3135 // checking can be done.\r
3136 //\r
3137 while (Count++ < 2) {\r
3138 NewPosition = NewPosition->BackLink;\r
3139 }\r
3140 } else {\r
3141 //\r
3142 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
3143 // to be one that progresses to the next set of op-codes, we need to advance to the last\r
3144 // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate\r
3145 // checking can be done.\r
3146 //\r
3147 while (Count-- > 0) {\r
3148 NewPosition = NewPosition->ForwardLink;\r
3149 }\r
3150 }\r
3151\r
3152 *CurrentPosition = NewPosition;\r
3153 }\r
3154\r
3155 return PadLineNumber;\r
3156}\r