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