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