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