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