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