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