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