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