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