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